关于PyCharm中可变默认参数的警告

问题描述 投票:21回答:3

我正在使用PyCharm(Python 3)编写一个Python函数,它接受一个字典作为attachment={}的参数。

def put_object(self, parent_object, connection_name, **data):
    ...

def put_wall_post(self, message, attachment={}, profile_id="me"):
    return self.put_object(profile_id, "feed", message=message, **attachment)

在IDE中,attachment={}是黄色的。将鼠标移到它上面会显示警告。

默认参数值是可变的

此检查检测何时在参数的默认值中检测到可变值作为列表或字典。

默认参数值仅在函数定义时计算一次,这意味着修改参数的默认值将影响函数的所有后续调用。

这意味着什么,我该如何解决?

python pycharm warnings
3个回答
33
投票

如果您不改变“可变默认参数”或将其传递到可以更改的任何地方,则忽略该消息,因为没有任何内容可以“修复”。

在您的情况下,您只需解压缩(隐式副本)“可变默认参数” - 所以您是安全的。

如果你想“删除那条警告信息”你可以使用None作为默认值,并在{}时将其设置为None

def put_wall_post(self,message,attachment=None,profile_id="me"):
    if attachment is None:
        attachment = {}

    return self.put_object(profile_id,"feed",message = message,**attachment)

只是为了解释“它意味着什么”:Python中的某些类型是不可变的(intstr,...)其他类型是可变的(如dictsetlist,...)。如果要更改不可变对象,则会创建另一个对象 - 但如果更改了可变对象,则该对象保持不变,但其内容会发生更改。

棘手的部分是在加载函数时(并且只加载一次)创建类变量和默认参数,这意味着对“可变默认参数”或“可变类变量”的任何更改都是永久性的:

def func(key, value, a={}):
    a[key] = value
    return a

>>> print(func('a', 10))  # that's expected
{'a': 10}
>>> print(func('b', 20))  # that could be unexpected
{'b': 20, 'a': 10}

PyCharm可能会显示此警告,因为很容易误将其弄错(例如参见“Least Astonishment” and the Mutable Default Argument和所有相关问题)。但是,如果你故意这样做(Good uses for mutable function argument default values?)警告可能很烦人。


4
投票

您可以使用None替换可变的默认参数。然后检查函数内部并指定默认值:

def put_wall_post(self, message, attachment=None, profile_id="me"):
    attachment = attachment if attachment else {}

    return self.put_object(profile_id, "feed", message=message, **attachment)

这是因为None评估为False所以我们然后分配一个空字典。

一般情况下,您可能需要明确检查None,因为其他值也可以评估为False,例如0''set()[]等都是False-y。如果您的默认值不是0并且例如是5,那么您不希望踩踏作为有效参数传递的0

def function(param=None):
    param = 5 if param is None else param

-2
投票

要重新警告警告:每次调用此函数(如果使用默认值)将使用相同的值。只要你永远不改变这个价值,它是可变的这一事实并不重要。但是如果你确实改变它,那么后续的调用将以修改后的值开始,这可能不是你想要的。

避免此问题的一种解决方案是将默认值设置为不可变值,如果使用该默认值,则将参数设置为{}

def put_wall_post(self,message,attachment=None,profile_id="me"):
    if attachment==None:
        attachment={}
    return self.put_object(profile_id,"feed",message = message,**attachment)
© www.soinside.com 2019 - 2024. All rights reserved.