类变量被所有实例共享是Python属性查找机制的自然结果,它直接存储在类的__dict__中,修改类变量需通过类名赋值,否则会创建实例属性。

类变量被所有实例共享,不是 Python 的缺陷或疏忽,而是对象模型和属性查找机制的自然结果——它就该这样工作。
类变量存在哪里?
类变量直接写在类体里、方法外,比如:species = "Canis familiaris"。Python 在执行类定义时,就把这个变量存进类对象的 __dict__,而不是每个实例的 __dict__。
这意味着:内存中只有一份 species,所有实例访问它时,都得“向上查”到类这一层。
- 打印
id(dog1.species)和id(dog2.species),结果相同(前提是没被覆盖) - 用
MyClass.__dict__.get("species")能直接看到它,但dog1.__dict__里没有 - 类变量生命周期与类一致:类加载即存在,程序退出才销毁
为什么修改后所有实例都“看见”了?
因为修改方式决定了影响范围:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
-
MyClass.species = "new"→ 直接改类的__dict__,所有实例下次访问都会拿到新值 -
dog1.species = "labrador"→ 不是改类变量,而是在dog1.__dict__新增一个同名键,从此dog1.species查找路径被截断(instance → class),不再触达类变量 -
dog1.toys.append("ball")(toys是类变量[])→ 没有赋值操作,只是调用方法,所以仍在原列表上修改,dog2.toys立刻可见
可变类变量为什么特别危险?
不可变类型(str、int)赋值会“遮蔽”,而可变类型(list、dict)的就地修改暴露了共享本质:
- 错误示范:
class Cache: data = {}→ 所有实例共用一个字典,缓存互相污染 - 安全写法:
def __init__(self): self.data = {}或self.data = dict(self.__class__.default_data) - 别用
None做默认值然后在方法里惰性初始化,除非你明确控制并发和重复创建逻辑
子类怎么正确更新父类的类变量?
子类实例不能靠 self.shared_var = ... 更新父类类变量——这只会新建实例属性。必须显式通过类名赋值:
- ✅ 正确:
Parent.shared_var = "updated"或self.__class__.__bases__[0].shared_var = ... - ❌ 错误:
self.shared_var = "updated"(创建实例属性)或Child.shared_var = ...(只影响 Child 及其后代,不触达 Parent 的其他子类) - 继承链中类变量是分层的:子类未定义时沿用父类;子类定义同名类变量,则覆盖查找路径,形成“局部共享”
真正容易被忽略的是:所谓“共享”,从来不是靠特殊标记实现的,而是 Python 属性查找规则(instance → class → parent classes)的必然推论。一旦你在实例上做了同名赋值,那条链就断了——你以为在改类变量,其实只是悄悄给自己贴了个标签。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










