Python中创建子类实例后父类类变量被意外修改的原因及解决建议
嗨Jan,我来帮你搞清楚这个问题的根源,以及怎么解决它~
问题原因:类变量的共享特性
你遇到的问题核心在于Python中类变量的共享机制。Parent类里的list1是一个类变量,而且它是可变类型(列表)。这意味着:所有继承自Parent的子类(Child1、Child2),以及它们的所有实例,都会共享同一个list1对象。
当你创建inst_child1时,Child1.__init__里调用super().list1.extend(self.list2),其实是直接修改了那个共享的父类list1。等你再创建inst_child2时,这个共享的list1已经被Child1修改过了,所以extend之后就会得到叠加的结果,而不是你预期的“Parent原始列表 + Child2元素”。
改进方案
这里有几种靠谱的解决办法,你可以根据需求选择:
方案1:把list1改为实例变量(最推荐)
让每个实例拥有自己独立的list1,这样就不会互相影响。修改Parent类的__init__:
class Parent: def __init__(self): # 把list1从类变量移到__init__里,变成实例变量 self.list1 = ['Parent_A', 'Parent_B'] # DO A LOT OF STUFF pass def get_list1(self): return self.list1 class Child1(Parent): list2 = ['Child1_A', 'Child1_B'] def __init__(self): super().__init__() # 现在修改的是当前实例自己的list1 self.list1.extend(self.list2) class Child2(Parent): list3 = ['Child2_A', 'Child2_B'] def __init__(self): super().__init__() self.list1.extend(self.list3)
这样每个实例初始化时都会得到全新的['Parent_A', 'Parent_B'],再添加自己的元素,互相之间完全独立。
方案2:在子类中创建类变量的副本
如果你需要保留Parent的类变量不变,或者有其他需求,可以在子类初始化时先复制父类的list1,再修改副本:
class Parent: list1 = ['Parent_A', 'Parent_B'] def __init__(self): # DO A LOT OF STUFF pass def get_list1(self): return self.list1 class Child1(Parent): list2 = ['Child1_A', 'Child1_B'] def __init__(self): super().__init__() # 复制父类的list1,作为当前实例的属性 self.list1 = super().list1.copy() self.list1.extend(self.list2) class Child2(Parent): list3 = ['Child2_A', 'Child2_B'] def __init__(self): super().__init__() self.list1 = super().list1.copy() self.list1.extend(self.list3)
这种方式下,Parent的原始list1不会被修改,每个子类实例操作的都是自己的副本。
补充说明
简单总结下类变量和实例变量的区别:
- 类变量:属于类本身,所有实例共享,修改类变量会影响所有实例(尤其是可变类型)。
- 实例变量:属于每个单独的实例,每个实例的实例变量都是独立的,修改不会影响其他实例。
你之前的误解在于以为“每次创建父类新实例时类变量会恢复默认值”,但实际上类变量是绑定在类上的,只有显式修改类本身的变量才会改变,实例创建不会重置类变量~
内容的提问来源于stack exchange,提问作者Jan
相关产品推荐
相关产品推荐

