了解Python的继承和初始化
问题描述:
可能重复:
“Least Astonishment” in Python: The Mutable Default Argument了解Python的继承和初始化
在Python 2.7,考虑我有以下代码:
class Base(object):
# Variant 1
def __init__(self, records=[]):
self._records = records
# Variant 2
# def __init__(self, records=[]):
# self._records = []
# if records:
# self._records = records
def append(self, value):
self._records.append(value)
class ChildA(Base):
pass
class ChildB(Base):
pass
a = ChildA()
b = ChildB()
a.append(100)
b.append(200)
print a._records
print b._records
如果我使用的变体1初始化我的基类self._records的行为就像一个类变量。执行使用变体1初始化我的基类中的代码,我得到的输出中:
[100, 200]
[100, 200]
使用变种2初始化我的基类,self._records就像一个实例变量(如预期)。执行使用变种2初始化我的基类中的代码,我得到的输出:
[100]
[200]
的是这两种变体之间的区别?为什么变体1的工作方式与变体2不同?非常感谢你的帮助!
答
它与继承,类或实例变量无关。考虑下面的代码:
>>> def f(a=[]):
... a.append(1)
... print a
...
>>> f.func_defaults
([],)
>>> f()
[1]
>>> f()
[1, 1]
>>> f.func_defaults
([1, 1],)
函数参数的默认值只被计算一个并存储在函数对象中。每次调用f
时,它都使用相同的列表进行操作。正如你的情况一样。
答
正如其他人所说的 - 这与使用空列表作为默认值有关,而不是类继承行为。
做正确的方法是:
class Base(object):
# Variant 1
def __init__(self, records=None):
if records is None:
records = []
self._records = records
因此确保一个新的列表实例每一个基类实例化时创建。将它放入代码中的方式是,在用Python解析类体时实例化一个列表对象 - 每次运行__init__
方法时,将使用list
的一个实例作为默认参数。由于对象拥有引用并更改同一列表,所以更改在共享Base
类的所有其他对象中都可见。