Why does initializing a variable via a python default variable keep state across object instantiation?
我今天遇到了一个有趣的python bug,在这个bug中,反复实例化一个类似乎处于保持状态。在以后的实例化调用中,已经定义了变量。
我将问题归结为以下类/shell交互。我认识到这不是初始化类变量的最佳方法,但它肯定不应该这样做。这是一个真正的bug还是一个"特性"?D
测试:
1 2 3 4 5 6 7 8 9 10 11 12 | class Tester(): def __init__(self): self.mydict = self.test() def test(self,out={}): key ="key" for i in ['a','b','c','d']: if key in out: out[key] += ','+i else: out[key] = i return out |
Python提示:
1 2 3 4 5 6 7 8 9 | Python 2.6.6 (r266:84292, Oct 6 2010, 00:44:09) [GCC 4.2.1 (Apple Inc. build 5664)] on darwin >>> import tester >>> t = tester.Tester() >>> print t.mydict {'key': 'a,b,c,d'} >>> t2 = tester.Tester() >>> print t2.mydict {'key': 'a,b,c,d,a,b,c,d'} |
这是几乎所有的Python用户都会遇到的一个特性。主要用于缓存等,以避免重复冗长的计算(实际上是简单的记忆化),尽管我确信人们已经找到了它的其他用途。
这样做的原因是,
通常情况下,人们都是这样工作的:
1 2 3 4 | def test(a=None): if a is None: a = {} # ... etc. |
通常,默认方法参数不应是可变的。而是这样做:
1 2 3 | def test(self, out=None): out = out or {} # other code goes here. |
请参阅这些链接,了解更多关于为什么需要这样做以及为什么它是Python语言的"特性"而不是bug的详细信息。
- "最小惊异"和可变的默认参数
- http://effbot.org/zone/default-values.htm(http://effbot.org/zone/default-values.htm)
您正在修改方法中的函数关键字参数
这篇博文简洁地解释了这一点:
expressions in default arguments are calculated when the function is defined, not when it’s called.
函数是在创建类时定义的,不是为每个实例定义的。如果您这样修改它,问题就消失了:
1 2 3 4 5 6 7 8 9 10 | def test(self,out=None): if out is None: out = {} key ="key" for i in ['a','b','c','d']: if key in out: out[key] += ','+i else: out[key] = i return out |