You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python继承中int与list类变量表现差异原因及统一实现咨询

为什么类变量n和lines行为不同?怎么让lines和n保持一致?

这个问题其实戳中了Python里类变量一个很容易踩的坑——不可变对象和可变对象在类继承中的行为差异,咱们来慢慢捋清楚:

一、先搞懂为什么n和lines表现不一样

1. 关于不可变对象n

n是整数,属于不可变类型。当你调用B.Add('hello')时,cls.n += 1这个操作其实是:

  • 先读取父类A中n的值(0)
  • 计算0 + 1 = 1
  • 给子类B创建一个属于它自己的类变量n,并赋值为1

之后B的n就和父类A的n彻底分家了,同理C调用Add时也会生成自己的n,所以最后两个子类的n都是独立的,值为1。

2. 关于可变对象lines

lines是列表,属于可变类型。cls.lines.append(line)这个操作是直接在原列表对象上修改,而不是创建新的列表。
因为B和C一开始都没有定义自己的lines类变量,所以它们会一直引用父类A的那个lines列表。不管是B还是C调用Add,都是在同一个列表里追加元素,最后自然会看到两个子类的lines都包含['hello', 'world']。

二、让lines和n行为一致的解决方案

你不想在每个子类里重新声明lines,那咱们可以在父类里做手脚,让每个子类自动拥有自己的lines:

方法1:用__init_subclass__(推荐,Python3.6+支持)

__init_subclass__是Python3.6新增的钩子,当子类被定义时会自动调用。我们在父类A里添加这个方法,给每个子类初始化独立的lines:

class A():
    n = 0
    lines = []
    @classmethod
    def Add(cls, line):
        cls.n += 1
        cls.lines.append(line)
    
    def __init_subclass__(cls):
        super().__init_subclass__()
        cls.lines = []  # 每个子类创建时都初始化自己的lines列表

class B(A):
    pass

class C(A):
    pass

B.Add('hello')
C.Add('world')
print(B.lines, B.n)  # 输出:['hello'] 1
print(C.lines, C.n)  # 输出:['world'] 1

方法2:在Add方法中动态检查(兼容旧版本Python)

如果你的Python版本低于3.6,可以在Add方法里检查当前类是否有自己的lines,没有就创建:

class A():
    n = 0
    lines = []
    @classmethod
    def Add(cls, line):
        cls.n += 1
        # 检查当前类是否拥有独立的lines,没有则创建
        if not hasattr(cls, 'lines'):
            cls.lines = []
        cls.lines.append(line)

class B(A):
    pass

class C(A):
    pass

B.Add('hello')
C.Add('world')
print(B.lines, B.n)  # 输出:['hello'] 1
print(C.lines, C.n)  # 输出:['world'] 1

这样就能让lines和n一样,每个子类都拥有独立的实例啦。

内容的提问来源于stack exchange,提问作者iain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 18:12:39