2011-05-16 72 views
6

可能重复:
“Least Astonishment” in Python: The Mutable Default Argument的Python:字典为实例变量

我对字典的类的实例变量的出现在Python 3的行为我的理解是很迷茫,Python中的实例变量具有每个实例存储的,不同于每个类的类变量(类似于一些其他语言称为“静态”)。

这似乎成立,除非实例变量是从默认参数创建的字典。例如:

class Foo: 
    def __init__(self, values = dict()): 
     self.values = values 

f1 = Foo() 
f1.values["hello"] = "world" 

f2 = Foo() 
print(f2.values) 

此程序输出:

{'hello': 'world'} 

咦?为什么实例f2f1具有相同的字典实例?

我得到预期的行为,如果我没有在一个空的字典作为默认的参数传递,只是分配self.values明确一个空的字典:

class Foo: 
    def __init__(self): 
     self.values = dict() 

但我不明白为什么这应该有什么区别。

+1

这可能是因为默认参数只会在加载类时评估一次。这样,你只是分配相同的参考作为默认参数。 – 2011-05-16 17:28:40

+0

堆栈溢出每个标记都有一个很好的“常见问题”功能。以下是Python标记的常见问题解答:http://stackoverflow.com/questions/tagged/python?sort=faq&pagesize=30您的问题在问题编号4处得到解答。 – 2011-05-16 18:30:35

回答

10

这是Python中众所周知的惊喜。当函数被定义时,而不是被调用时,默认参数被评估。所以你的默认参数是对一个共同的dict的引用。它与分配给类/实例变量无关。

如果您想使用默认参数,使用None,并检查它:

if values is None: 
    self.values = {} 
else: 
    self.values = values 
+1

您将在列表中获得相同的行为 – jaydel 2011-05-16 17:30:54

+2

您将获得与每个*可变对象相同的行为。 – delnan 2011-05-16 17:50:36

2

默认值只计算一次。你想要的东西是这样的:

class Foo: 
    def __init__(self, values = None): 
     self.values = values or dict() 

如果你提供values,那会被使用。如果不是,则valuesor运算符评估为FALSE,并实例化新的字典。

+2

如果有任何虚假信息作为值传递,这会失败 - 例如,一个自定义的'dict'子类的空实例。 – delnan 2011-05-16 18:02:16