Python继承场景下list.append()为何出现异常行为?
问题根源:类变量被所有实例共享
你遇到的问题核心是类属性与实例属性的混淆:
- 你的
__Parent类中,var = []是类变量,属于整个类而非单个实例。这意味着所有__Parent的子类实例(包括ChildOne和ChildTwo的实例)都会共享同一个列表对象。 - 当
ChildTwo中调用self.var.append(ChildOne())时,本质是在修改这个全局共享的类列表,所以ChildOne实例的var自然也能看到这个新增的元素——因为它们指向的是同一个列表。
而numpy.append()的行为看起来符合预期,是因为它的特性:numpy.append()不会修改原数组,而是返回一个新的数组对象。当你执行self.var = np.append(self.var, ChildOne())时,相当于给当前ChildTwo实例创建了一个属于自己的var实例属性,覆盖了原本继承的类属性。这时候ChildOne实例的var还是原来的空类列表,所以长度为0,符合你的预期。
修复方案:将类变量改为实例变量
要解决这个问题,只需要把var从类属性改为实例属性,在__Parent的构造方法里初始化:
import numpy as np class __Parent: i_am_from_child = None def __init__(self, which:str=None) -> None: self.i_am_from_child = which self.var = [] # 在这里初始化实例变量,每个实例拥有独立的列表 print(f"Parent initiallized by Child{which}") def how_long(self) -> int: return len(self.var) def from_child(self) -> str: return self.i_am_from_child class ChildOne(__Parent): def __init__(self) -> None: print("Initiallizing ChildOne") super().__init__(which="One") print(f"ChildOne: len(self.var) = {len(self.var)}") class ChildTwo(__Parent): def __init__(self) -> None: print("Initiallizing ChildTwo") super().__init__(which="Two") self.var.append(ChildOne()) # 现在操作的是当前实例的独立列表 # self.var = np.append(self.var, ChildOne()) # 这个也能正常工作 # 测试代码 X = ChildTwo() Y = X.var[0] print(f"type(X) = {type(X)} and type(Y) = {type(Y)}") print(f"X is from Child{X.from_child()} and Y=X.var[0] is from Child{Y.from_child()}") print() print(f"ChildOne: self.function() = {Y.how_long()} should be 0") print(f"ChildTwo: self.function() = {X.how_long()} should be 1") # 现在Y.var是空列表,访问Y.var[0]会报错,符合预期 # print(f"Type of Y.var[0] is {type(Y.var[0])}")
运行修改后的代码,你会得到预期的结果:
Y.how_long()返回0(ChildOne实例的var是空列表)X.how_long()返回1(ChildTwo实例的var包含一个ChildOne对象)
内容的提问来源于stack exchange,提问作者bjoernzy
相关产品推荐
相关产品推荐

