Python中为什么类和实例的__dict__保存的内容不同?(MRO)
已于 2025年10月12日 11:15 修改
访问次数:0
🧩 Python 实例的 __dict__ 为什么只包含实例变量
一、基本概念对比
| 名称 | 存放内容 | 所属对象 | 存放位置 |
|---|---|---|---|
| 类变量 | 定义在类体中的属性(所有实例共享) | 属于类 | 类.__dict__ |
| 实例变量 | 每个对象独有的属性(通常在 __init__ 中定义) | 属于实例 | 实例.__dict__ |
二、对象属性的查找顺序(MRO)
当你访问 obj.attr 时,Python 按以下顺序查找:
1️⃣ obj.__dict__(实例自己的命名空间)
2️⃣ obj.__class__.__dict__(类的命名空间)
3️⃣ 父类的 __dict__(沿 MRO 继承链查找)
4️⃣ 最终到 object
💡 因此:
- 实例能“访问”类变量(通过查找链找到),
- 但它不拥有类变量(因为类变量存在于类的命名空间中)。
三、__dict__ 的真实含义
__dict__ 不是“变量表”,而是对象的 命名空间字典 (所有“该对象自己拥有的属性”的键值对)。
- 类的 __dict__ → 存放类定义时绑定的名字:类变量、方法、描述符等。
- 实例的 __dict__ → 仅存放该实例通过 self.xxx = ... 绑定的属性。
因此:
class Student:
school = "Python大学" # 类变量
def __init__(self, name):
self.name = name # 实例变量
s = Student("Alice")
print(Student.__dict__) # 含 school, __init__
print(s.__dict__) # 只含 {'name': 'Alice'}
四、为什么实例不包含类变量
✅ 1. 节省内存
类变量是共享的,没必要复制到每个实例中。
✅ 2. 动态绑定与继承
通过查找链(MRO)机制,实例访问类变量依然可见;
这样类中修改变量,所有实例立即生效。
✅ 3. 写入时独立
当你执行:
s.school = "别的学校"Python 不会修改类的属性,而是直接在 s.__dict__ 中新建 'school',覆盖查找结果。
五、验证示例
class A:
x = 1
a = A()
b = A()
print(a.x, b.x) # 1 1(从类查找)
A.x = 2
print(a.x, b.x) # 2 2(共享变化)
a.x = 3
print(a.x, b.x, A.x)
# 3 2 2(a有自己的x,不再用类的)
a.__dict__ → {'x': 3}A.__dict__ → {'x': 2, ...}
六、总结一句话 ✅
实例的 __dict__ 只包含实例自己拥有的属性(实例变量), 因为类变量属于类的命名空间,实例只是通过属性查找机制“能看到”它们, 并不会在自己的命名空间里复制一份。
七、类与实例属性关系图
Class: A
├── __dict__ = { 'x': 1, '__init__': <function> }
Instance: a
├── __dict__ = { 'y': 2 }
访问 a.x 时:
→ 查 a.__dict__(没有)
→ 查 A.__dict__(找到 x=1)
评论(2)
tongqing
搞错了,不能用变量角度去看这个问题。用attribute去看这个问题,这个问题就是namespace和MRO的问题。符合python设计
2025年10月12日 11:19tongqing
python对象模型的核心哲学: “在 Python 里,一切绑定到对象上的名字都是 attribute(属性),不是变量。”
2025年10月12日 11:21