Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python class inheritance and __dict__ lookup [duplicate]

Let's say I define class A:

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

Then I define class B that inherits from A:

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

Now, check __dict__ of A and __dict__ of B:

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

Somehow, B.__dict__ contains neither 'a' nor 'SubA'. Now if we do:

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

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

First question: why B.__dict__ does not contain 'a' and 'SubA'? Second question: Why B.a and B.SubA give the expected results, although neither 'a' nor 'SubA' is in B's __dict__?

Thanks!

like image 589
jazzblue Avatar asked May 07 '14 23:05

jazzblue


2 Answers

@bgporter has given a good explanation of the behaviour, I'll just go into why a little:

If your class variable was in B.__dict__, how would it function? Each subclass would have its own value for a, independent of the value for A.a - this is not what you would expect. A class variable should exist once - in that class.

Instead, Python does a lookup on the class and if it doesn't exist, then looks up to its base classes - note that means it is possible to shadow a class variable in a subclass.

like image 153
Gareth Latty Avatar answered Oct 01 '22 11:10

Gareth Latty


That's how Python's object model works:

A class has a namespace implemented by a dictionary object. Class attribute references are translated to lookups in this dictionary, e.g., C.x is translated to C.__dict__["x"] (although for new-style classes in particular there are a number of hooks which allow for other means of locating attributes). When the attribute name is not found there, the attribute search continues in the base classes.

like image 30
bgporter Avatar answered Oct 01 '22 13:10

bgporter