Python中为什么类和实例的__dict__保存的内容不同?(MRO)

🧩 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:19
用户头像
tongqing

python对象模型的核心哲学: “在 Python 里,一切绑定到对象上的名字都是 attribute(属性),不是变量。”

2025年10月12日 11:21