python中的可变默认值

时间:2013-10-20 22:10:06

标签: python

class Foo:
    def __init__(self, stuff = []):
        print(stuff)
        self.stuff = stuff
    def add(self,x):
        self.stuff.append(x)


>>>f = Foo()
[]
>>>f.add(1)
>>>g = Foo()
[1]

我只对代码进行了一次更改(第4行)

class Foo:
    def __init__(self, stuff = []):
        print(stuff)
        self.stuff = stuff or []
    def add(self,x):
        self.stuff.append(x)


>>>f = Foo()
[]
>>>f.add(1)
>>>g = Foo()
[] 

我改变了第4行中的某些内容但导致了打印结果的变化(在第3行中)

我只是想知道它是如何运作的。

2 个答案:

答案 0 :(得分:1)

在这一行:

def __init__(self, stuff = []):

使用Foo()创建的所有实例都将使用相同的列表,作为__init__所有调用的默认值创建。这就是为什么在第一个示例中向f添加任何内容会导致修改所有 Foo的更多实例的默认列表。这是因为当解释器评估stuff = []行时,将评估部分def。来自documentation

  

执行定义功能时,将评估默认参数值。这意味着当定义函数时,表达式被计算一次,并且每次调用使用相同的“预先计算”值。

(我加粗)。

在第二个示例中,由于默认值始终为空,因此将评估or子句的第二部分,每次创建Foo的新实例时,该子句将创建一个新的单个列表实例。因此,所有Foo个实例都有自己的列表。

Here您可以找到更多解释和示例。

答案 1 :(得分:1)

作为回退参数值传递的列表会被实例化一次,并在每次调用__init__时重复使用。因此,向其中添加值将传播到Foo的每个下一个实例。

第一个和第二个例子之间的差异是stuff or []。您需要知道 empty 列表,当作为布尔值计算为False时,如果stuff or []为空,stuff表达式将返回第二个操作数,在你的例子中总是如此。第二个操作数是在方法调用中实例化的列表,因此每次调用__init__时都是不同的实例。这可确保增加的值不会传播。