Наследование классов Python и поиск __dict__
Допустим, я определяю класс A:
>>> class A:
... a = 1
... class SubA:
... sub_a = { 'a': 1, 'b': 1}
Затем я определяю класс B, который наследуется от A:
>>> class B(A):
... pass
Теперь проверьте __dict__ из A и __dict__ из B:
>>> 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"? Второй вопрос: почему Ba и B.SubA дают ожидаемые результаты, хотя ни "a", ни "SubA" не входит в __dict__B?
Спасибо!
2 ответа
@bgporter дал хорошее объяснение поведения, я просто пойду, почему немного:
Если ваша переменная класса была в B.__dict__
как бы это функционировало? Каждый подкласс будет иметь свое значение для a
независимо от значения для A.a
- это не то, что вы ожидаете. Переменная класса должна существовать один раз - в этом классе.
Вместо этого Python выполняет поиск класса и, если он не существует, ищет его базовые классы - обратите внимание, это означает, что можно скрыть переменную класса в подклассе.
Вот как работает объектная модель Python:
Класс имеет пространство имен, реализованное объектом словаря. Ссылки на атрибуты класса преобразуются для поиска в этом словаре, например,
C.x
переводится наC.__dict__["x"]
(хотя для классов нового стиля, в частности, есть ряд хуков, которые допускают другие способы определения местоположения атрибутов). Когда имя атрибута там не найдено, поиск атрибута продолжается в базовых классах.