Найти тему
Python Django

О наследовании атрибутов

О наследовании атрибутов

Видел тут на одном из каналов задачку про поле класса и наследование. Загадывать вам ее не буду, но объяснение приведу. Пусть:

class Abram:

foo = 10

class Barak(Abram):

pass

class Clara(Barak):

pass

print(Abram.foo, Barak.foo, Clara.foo) # 10 10 10

Тут понятно и новичку, что поле foo вроде как "наследуется" классами Barak и Clara у класса Abram. Однако, давайте попробуем его поменять:

Abram.foo = 20

print(Abram.foo, Barak.foo, Clara.foo) # 20 20 20

Barak.foo = 30

print(Abram.foo, Barak.foo, Clara.foo) # 20 30 30

Abram.foo = 40

print(Abram.foo, Barak.foo, Clara.foo) # 40 30 30

Видим, что у класса Barak и Clara значение стало 30, а Abram.foo живет своей жизнью после Barak.foo = 30 и не перестало влиять на прочие классы.

Работает это так. При поиске атрибута класса сначала спрашивается у самого класса, есть ли у него этот атрибут, если да, то он вернется, если нет, то идут к следующему классу, который старше по иерархии наследования (Clara → Barak → Abram → object). Если у него тоже нет, то идут еще дальше, пока не найдут, иначе возникнет исключение AttributeError.

В нашем примере будем рассуждать с конца. Чему равно Clara.foo? Есть ли атрибут foo у Clara? Вообще говоря, его нет, ведь мы ни разу не присваивали ничего к Clara.foo:

>>> 'foo' in Clara.__dict__

False

Предок класса Clara – класс Barak. Как только мы написали Barak.foo = 30 в классе Barak появился свой собственный foo:

>>> Barak.foo = 20

>>> 'foo' in Barak.__dict__

True

А до этого атрибут foo был изначально только у Abram. Если теперь написать Clara.foo = 50, то у каждого из классов будет свой foo.

Clara.foo = 50

print(Abram.foo, Barak.foo, Clara.foo) # 40 30 50

Вывод: как только мы присвоим атрибут, то атрибуты классов-предков перестают на него влиять. Будьте внимательны, ведь такая же логика действует и для методов класса.

@pro_python_code