1
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 行)

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

4

2 回答 2

1

您作为后备参数值传递的列表被实例化一次,并在每次调用__init__. 因此,向其中添加一个值将传播到Foo.

第一个例子和第二个例子的区别是stuff or []。您需要知道一个列表,当评估为布尔值时Falsestuff or []如果为空,则表达式返回第二个操作数stuff,在您的示例中总是如此。第二个操作数是在方法调用中实例化的列表,因此每次调用时都会有不同的实例__init__。这确保了附加值不会传播。

于 2013-10-20T22:19:41.477 回答
1

在这一行:

def __init__(self, stuff = []):

使用创建的所有实例Foo()将使用相同的列表,创建为所有调用的默认值__init__。这就是为什么在第一个示例中添加任何内容会f导致修改所有其他实例的默认列表Foo。这是因为在stuff = []解释器评估该def行时会评估该部分。从文档中:

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

(由我加粗)。

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

在这里你可以找到更多的解释和例子。

于 2013-10-20T22:19:20.150 回答