Python方法:默认参数值在ONCE中计算

sha*_*sir 7 python dictionary super

我在New-Style Classes中发现了子类化和字典更新的一个奇怪问题:

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}
>>>
Run Code Online (Sandbox Code Playgroud)

在debug中,在第二个call(c(3))中,您可以看到a构造函数self.props中已经等于{'arg': 2},并且在此b之后调用构造函数时,它将成为{'arg': 3}两个对象!

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

  a, b    # for b(2)
  c, a, b # for c(3)
Run Code Online (Sandbox Code Playgroud)

如果你会改变self.props.update()self.props = {'arg': val}b构造函数中,一切都会好的,如预期将采取行动

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

Chr*_*ard 11

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

class a(object):
    def __init__(self, props=None):
        if props is None:
            props = {}
        self.props = props
Run Code Online (Sandbox Code Playgroud)

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


Nad*_*mli 7

你的问题在于这一行:

def __init__(self, props={}):
Run Code Online (Sandbox Code Playgroud)

{}是一种可变类型.并且在python默认参数值中只评估一次.这意味着您的所有实例都共享相同的字典对象!

要解决此问题,请将其更改为:

class a(object):
    def __init__(self, props=None):
        if is None:
            props = {}
        self.props = props
Run Code Online (Sandbox Code Playgroud)