的Python / Django的随机DB查询结果由于“默认参数值是可变的”在方法

问题描述 投票:0回答:1

昨天我在我的Django应用程序时遇到一个错误,尽管我因为固定它,我还是不明白其原因,无论是我如何解决它。

嗯,其实我发现的根本原因,而写了这个问题,这要归功于SO“的问题有类似的标题”功能。见"Least Astonishment" and the Mutable Default Argument

Buuut,我还是不明白怎么会影响我的应用程序在它影响的方式。所以,让我们挖英寸

我有一个网页,该网页显示的项目清单。我通过Model.get方法查询这些项目,从views.py文件。没有什么两样,基本上从模型获取数据库,调用视图中的模型,并提供可变所述提取值的模板。

当使用错误的源代码,我会刷新页面,该项目将随机出现两种或消失。我想通了DB查询将要么返回的项目,或者返回一个空列表。

下面是有故障的源代码(model.py):

  @classmethod
  def get(cls, school=None, additional_filters={}):
    if school:
      additional_filters['school'] = school

    return MyModel.objects.filter(
      **additional_filters
    )

这里是我如何固定它:

  @classmethod
  def get(cls, school=None, additional_filters=None):
    if not additional_filters:
      additional_filters = {}

    if school:
      additional_filters['school'] = school

    return MyModel.objects.filter(
      **additional_filters
    )

我修好了这种方式,因为PyCharm IDE告诉我有什么不对劲Default argument value is mutable,因为我无法解释的漏洞可言,我跟着它的建议。

但我还是不明白为什么。即使是现在,看完后"Least Astonishment" and the Mutable Default Argument我还是不知道。

我现在明白了additional_filters在每次调用修改由于到Python处理内存中的函数默认参数的方式。

我不解释是此行为的副作用。为什么查询返回任何适当的项目或一个空集?特别是考虑到该代码没有提供任何additional_filters,在additional_filters意味着只增加项目是school它总是在每一个查询相同。

这就是我真的不明白的部分。我对这种方法的所有电话都是形式Model.get(request.context.school),自此additional_filters是地图,而不是一个数组,它应该永远都包含在相同的值。

这个bug花了我一段时间来弄清楚,因为我无法重现它在我的当地环境,也没有临时环境,它仅影响生产环境,并使其非常非常难以定位。

python django pycharm mutable
1个回答
2
投票

FCGI维护的过程池。每个池的成员有一个空的字典作为默认关键字参数。 你最初是幸运的,请求到达与不变空字典的过程。但每当请求达到其已经改变了这本词典的过程中,那么它是不是一个空的字典了 - 你的过滤器积累。

© www.soinside.com 2019 - 2024. All rights reserved.