Python类变量被所有实例共享是设计使然,源于类命名空间和属性查找机制;类变量存于类__dict__中,实例访问时若无同名属性则向上查找;不可变类型赋值会创建实例属性覆盖查找路径,可变类型修改则暴露共享本质。

Python 类变量确实被所有实例共享,这不是 bug,而是语言设计的必然结果——它源于类对象的命名空间和 Python 的属性查找机制。
类变量在内存中只有一份,所有实例共用同一引用
当你在类体中直接定义 species = "Canis lupus",这个赋值发生在类定义执行时,Python 会把该变量存入类的 __dict__,而不是每个实例的 __dict__。所有实例访问 dog1.species 或 dog2.species 时,若实例自身没有同名属性,就会向上查找到类层级。
- 不可变类型(如
int、str)看似“不共享”:因为a.var = 1实际是给实例新建了同名属性,覆盖了类变量的查找路径 - 可变类型(如
list、dict)暴露共享本质:调用a.toys.append("ball")是在原对象上修改,b.toys自然看到变化 - 验证方式:打印
id(dog1.species)和id(dog2.species),若为类变量且未被覆盖,两者相同
实例变量必须在 __init__ 或方法内用 self.xxx = ... 显式创建
只有通过 self 绑定的变量才进入实例命名空间,每次实例化都会生成独立副本。漏写 self 是新手高频错误。
- 错误写法:
def __init__(self, name): toys = []→toys是局部变量,函数结束即销毁 - 正确写法:
def __init__(self, name): self.toys = []→ 每个实例都有自己的空列表 - 如果想初始化类变量的副本,需在
__init__中显式复制:self.toys = list(self.__class__.default_toys)
类变量适合存默认配置或跨实例状态,但别用它存可变默认值
类变量天然适合计数器、版本号、枚举常量等只读或受控更新的数据;但用它做可变容器(如 list、dict)作为“默认值”,几乎必然导致数据污染。
- 典型陷阱:
class Cache: data = {}→ 所有实例操作的都是同一个字典 - 安全替代方案:在
__init__中初始化可变对象,或用None做占位符再惰性创建 - 性能提示:类变量访问比实例变量略快(少一次字典查找),但差异微乎其微,不该成为滥用理由
真正容易被忽略的是:类变量的“共享”不是靠魔法实现的,而是 Python 对象模型中命名空间链(instance → class → parent classes)的自然结果。一旦你开始在实例上直接赋值同名变量,就切断了这条链——这时候你以为改的是类变量,其实只是给自己加了个影子属性。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











