实例赋值 self.xxx = 会创建新属性而非修改类变量;可变类变量(如list、dict)被原地修改导致数据污染,不可变类型则无此问题;正确做法是在__init__中初始化实例属性。

实例赋值 self.xxx = 会创建新属性,不是修改类变量
当你在方法里写 self.items = [],Python 永远只往当前实例的 __dict__ 里塞一个新键值对,完全不碰类的 __dict__。哪怕类里早有同名的 items,它也视而不见。
这导致看似“改了类变量”,实际只是给自己加了个影子属性。其他实例照旧读取类变量,于是数据不一致。
-
MyClass.items = [1, 2]→ 真正修改类变量,所有未覆盖的实例立刻看到变化 -
obj.items = [1, 2]→ 只给obj新建实例属性,MyClass.items不变 -
obj.items.append(3)→ 若obj.items还没被赋值过,就真在类变量上原地修改
可变类型暴露共享本质,不可变类型掩盖问题
类变量如果是 list、dict 这类可变对象,调用 .append()、.update() 就直接改内存里的原对象;而 int、str 被“赋值”时其实是绑定新对象,旧对象不受影响。
所以你常看到:两个实例都往 MyClass.cache(字典)里存东西,结果互相污染;但改 MyClass.version = 2 却不会影响别人——因为后者根本没动原来的整数对象。
立即学习“Python免费学习笔记(深入)”;
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
- 错误示范:
class Cache: data = {}→ 所有实例共用一个字典 - 安全写法:
def __init__(self): self.data = {}→ 每个实例独享 - 若真要共享可变状态,必须显式加锁或用线程安全结构
访问优先级和修改逻辑是两套规则
读的时候走“实例 → 类 → 父类”,写的时候 self.xxx = 永远只写实例;想改类变量,必须用 MyClass.xxx = 或 type(obj).xxx =。
很多人卡在“我明明改了 obj.flag,为什么别的实例还是旧值?”——因为你改的是自己的 flag,不是类的。
-
print(obj.flag)→ 先查obj.__dict__.get('flag'),找不到才查类 -
obj.flag = True→ 强制写入obj.__dict__['flag'],类变量不动 -
MyClass.flag = True→ 修改类的__dict__,所有未覆盖的实例立即生效
继承中同名类变量容易引发隐性覆盖
子类定义同名类变量,不是覆盖父类变量,而是新建一个独立的类变量。父类和子类的同名变量互不影响,但实例查找时会按 MRO 顺序优先匹配最近的定义。
比如 Parent.count = 0,Child.count = 0,然后 Child().count += 1,只改 Child.count,Parent.count 仍是 0。但如果你漏写子类定义,实例就会回退到读 Parent.count,行为变得不一致。
- 别依赖“子类自动继承并共享父类可变类变量”
- 需要跨层级共享状态时,显式用
Parent.shared_state并文档说明 - 用
is检查是否真指向同一对象:Child.count is Parent.count通常为False

















