Python:新类实例中未创建变量的新实例
我发现了Python的一些奇怪行为(或者说我可能不太理解继承和属性默认值是怎么工作的)。
对于下面这段代码:
class A(object):
def __init__(self, s):
self.s = s
print "in init", self.s
class B(A):
def __init__(self, s = set()):
super(B, self).__init__(s)
print "after super", self.s
self.s.add('foo')
print '--------------'
if __name__ == "__main__":
a = B()
b = B()
我得到了以下输出:
in init set([])
after super set([])
--------------
in init set(['foo']) # Why it has value set in other object?!
after super set(['foo'])
--------------
当然,我希望第二个对象(b)里的self.s能用一个空集合来初始化,但不知道为什么它却从前一个对象那里获取了状态。这是为什么呢?我该怎么才能得到我想要的结果呢?
谢谢!
2 个回答
1
当你为一个参数设置默认值时,这个值是在你定义函数的时候计算出来的,而不是在你调用这个函数的时候。所以,它使用的是在你定义类的时候创建的那个set()
,并且不断往里面添加更多的项目。
通常在Python中,我们的做法是把默认值设置为None
,然后在__init__
函数里明确地初始化一个新的set()
(或者列表、字典,或者你想要的任何对象)。
class B(A):
def __init__(self, s=None):
if s is None:
s = set()
9
你遇到了可变默认参数的陷阱。你在类 B 的 __init__
方法中指定的 set()
作为默认值,其实是同一个对象,这个对象会被传递给你创建的每一个新的 B
实例。把它放到 self
中并不会创建一个新的副本,而只是创建了对同一个对象的引用。
你可能想要在每个新对象中创建一个副本,所以需要明确地这样做:
class A(object):
def __init__(self, s):
self.s = copy.copy(s)