类属性存于类对象的__dict__中,被所有实例共享;访问时通过“实例→类”查找机制获取,修改需用类名赋值,否则会创建同名实例属性遮蔽类属性。

Python 中的类属性在所有实例之间共享,不是 bug,而是对象模型和属性查找机制共同作用的必然结果。
类属性存在哪里?
类属性写在类体里、方法外,比如 species = "Canis familiaris",Python 在执行类定义时,就把这个变量存进类对象的 __dict__ 里,而不是每个实例的 __dict__。
这意味着:
- 内存中只有一份该对象,所有实例访问它时都得“向上查”到类这一层
-
id(instance1.attr)和id(instance2.attr)相同(前提是没被覆盖) -
MyClass.__dict__.get("attr")能直接拿到它,但instance.__dict__里没有
为什么改了之后所有实例都“看见”?
关键看你怎么改:
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
立即学习“Python免费学习笔记(深入)”;
-
MyClass.attr = "new"→ 直接更新类的__dict__,所有实例下次访问都会拿到新值 -
instance.attr = "new"→ 不是改类变量,而是在该实例的__dict__新增一个同名键,从此它的查找路径被截断(instance → class),不再触达类变量 -
instance.mutable_attr.append(x)(如list或dict)→ 没有赋值操作,只是调用方法,仍在原对象上修改,其他实例立刻可见
可变类属性为什么特别危险?
不可变类型(int、str)赋值会“遮蔽”,而可变类型(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)的自然推论。一旦你在实例上做了同名赋值,那条链就断了——你以为在改类变量,其实只是给自己加了个影子属性。

















