Python 类继承与 __dict__ 查找
假设我定义了一个类 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)一个类变量。