Python 类继承与 __dict__ 查找

6 投票
2 回答
6913 浏览
提问于 2025-04-18 05:45

假设我定义了一个类 A:

>>> class A:
...     a = 1
...     class SubA:
...         sub_a = { 'a': 1, 'b': 1}

然后我定义了一个类 B,这个类是从 A 继承过来的:

>>> class B(A):
...     pass

现在,我们来看看 A 和 B 的 __dict__

>>> A.__dict__
{'a': 1, '__module__': '__builtin__', '__doc__': None, 'SubA': <class __builtin_ _.SubA at 0x02CAA3E8>}
>>> B.__dict__
{'__module__': '__builtin__', '__doc__': None}

奇怪的是,B.__dict__ 里既没有 'a' 也没有 'SubA'。现在如果我们这样做:

>>> A.a
1
>>> B.a
1

>>> A.SubA
<class __builtin__.SubA at 0x02CAA3E8>
>>> B.SubA
<class __builtin__.SubA at 0x02CAA3E8>

第一个问题:为什么 B.__dict__ 里没有 'a''SubA'

第二个问题:虽然 'a''SubA' 都不在 B__dict__ 里,但为什么 B.a 和 B.SubA 还能给出预期的结果呢?

谢谢!

2 个回答

5

这就是Python的对象模型的工作原理:

一个类有一个命名空间,这个命名空间是通过一个字典对象来实现的。类的属性引用会被转换成在这个字典中的查找,比如说,C.x会被转换成C.__dict__["x"](不过对于新式类来说,还有一些其他的方法可以用来找到属性)。如果在这个字典里找不到属性名,系统会继续在基类中查找。

9

@bgporter 对这个行为做了很好的解释,我这里简单说说为什么

如果你的类变量在 B.__dict__ 里,那它是怎么工作的呢?每个子类都会有自己独立的 a 的值,这和 A.a 的值没有关系——这可不是你所期望的。一个类变量应该只在那个类里存在一次。

相反,Python 会先在类里查找这个变量,如果找不到,就会往上查找它的父类——这意味着在子类里可以覆盖(shadow)一个类变量。

撰写回答