关于字典:Python方法:默认参数值在ONCE中计算

Python methods: default parameter values are evaluated ONCE

我发现在新的样式类中,子类化和字典更新有一个奇怪的问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Python 2.6.2 (r262:71605, Apr 14 2009, 22:40:02) [MSC v.1500 32 bit (Intel)] on
win32
>>> class a(object):
...     def __init__(self, props={}):
...             self.props = props
...
>>> class b(a):
...     def __init__(self, val = None):
...             super(b, self).__init__()
...             self.props.update({'arg': val})
...
>>> class c(b):
...     def __init__(self, val):
...             super(c, self).__init__(val)
...
>>> b_inst = b(2)
>>> b_inst.props
{'arg': 2}
>>> c_inst = c(3)
>>> c_inst.props
{'arg': 3}
>>> b_inst.props
{'arg': 3}
>>>

在DEBUG中,在第二个调用(c(3)中,您可以看到在a构造函数self.props中已经等于{'arg': 2}了,之后调用b构造函数时,两个对象都变成{'arg': 3}了!

另外,构造函数调用的顺序是:

1
2
  a, b    # for b(2)
  c, a, b # for c(3)

如果用b构造函数中的self.props = {'arg': val}来更改self.props.update(),一切都会正常,并且会按预期工作。

但我真的需要更新这个属性,而不是替换


props不应该有这样的默认值。改为这样做:

1
2
3
4
5
class a(object):
    def __init__(self, props=None):
        if props is None:
            props = {}
        self.props = props

这是一个常见的python"gotcha"。


您的问题在这一行:

1
def __init__(self, props={}):

是可变类型。在python中,默认参数值只计算一次。这意味着所有实例都共享同一个字典对象!

要修复此问题,请将其更改为:

1
2
3
4
5
class a(object):
    def __init__(self, props=None):
        if is None:
            props = {}
        self.props = props


简短版本:执行此操作:

1
2
3
4
5
6
7
8
9
10
11
12
class a(object):
    def __init__(self, props=None):
        self.props = props if props is not None else {}

class b(a):
    def __init__(self, val = None):
        super(b, self).__init__()
        self.props.update({'arg': val})

class c(b):
    def __init__(self, val):
    super(c, self).__init__(val)

长版本:

函数定义只计算一次,因此每次调用它时都使用相同的默认参数。要使其按预期工作,每次调用函数时都必须计算默认参数。但是,python只生成一次函数对象,并将默认值添加到对象中(如func_obj.func_defaults)