为什么通过Python默认变量初始化的变量在对象实例化之间保持状态?
今天我遇到了一个有趣的Python问题,就是反复创建一个类的实例时,似乎会保持某种状态。在后续的实例化调用中,变量已经被定义了。
我把这个问题简化成了以下的类和命令行的互动。我知道这不是初始化类变量的最佳方式,但它的表现确实不应该是这样的。这算不算一个真正的bug,还是说这是个“特性”?:D
tester.py:
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提示符:
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'}
3 个回答
3
你正在修改方法中函数参数 out
的值。
这篇博客文章 简单明了地解释了这个问题:
默认参数中的表达式是在函数定义的时候计算的,而不是在函数被调用的时候。
函数是在类创建的时候定义的,而不是为每个实例单独定义的。如果你这样修改,就能解决这个问题:
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
5
一般来说,默认的方法参数不应该是可变的。相反,应该这样做:
def test(self, out=None):
out = out or {}
# other code goes here.
想了解更多为什么这样做是必要的,以及为什么这被认为是Python语言的一个“特性”而不是一个错误,可以查看这些链接。
15
这是一个几乎所有Python用户都会遇到的功能,通常会碰到一两次。它的主要用途是用来缓存数据,避免重复进行耗时的计算(其实就是简单的记忆化),不过我相信大家也会找到其他的用法。
原因在于,def
语句只会执行一次,也就是在定义函数的时候。因此,初始化的值只会创建一次。对于像列表或字典这样的引用类型(与不可变类型不同,不可变类型是不能改变的),这就会变成一个明显且令人惊讶的陷阱,而对于值类型来说,这种情况通常不会被注意到。
通常,人们会这样来解决这个问题:
def test(a=None):
if a is None:
a = {}
# ... etc.