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行中)
我只是想知道它是如何运作的。
答案 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__
时都是不同的实例。这可确保增加的值不会传播。