Перейти до змісту

Лінеаризація

Як ми вже з'ясували, дочірній клас може не мати певного атрибута, але він може успадкувати його від базового класа. Для пошуку атрибутів в ієрархії класів використовується лінеаризація класів.

Лінеаризація — це черговість, при якій проводиться пошук зазначеного атрибута в ієрархії класів.

Використовуючи лінеаризацію відбувається пошук атрибутів в ієрархії класів. При простому успадкуванні алгоритм пошуку атрибутів виглядає наступним чином:

  • якщо атрибут, до якого відбувається доступ, не знайдено в поточному класі, то виконується його пошук в базовому класі
  • якщо атрибут не знайдено і в базовому класі, то виконується його пошук в базовому класі базового класа
  • пошук відбувається рекурсивно аж до класа object
  • якщо атрибут не знайдено і в класі object, то отримуємо вийняткову ситуацію

Приклад:

>>> class SuperBase:
...     def f1(self):
...         print('Метод f1() класа SuperBase')
...
>>> class Base(SuperBase):
...     def f2(self):
...         print('Метод f2() класа Base')
...
>>> class Child(Base):
...     def f2(self):
...         print('Метод f2() класа Child')
...     def f3(self):
...         print('Метод f3() класа Child')
...
>>>

У вищенаведеному прикладі клас Child:

  • від класа SuperBase успадкував метод f1()
  • з батьківського класа метод f2() не успадковується, клас має власний метод f2()
  • має власний метод f3()

Перевіримо на практиці:

>>> child_object = Child()
>>> child_object.f1()
Метод f1() класа SuperBase
>>> child_object.f2()
Метод f2() класа Child
>>> child_object.f3()
Метод f3() класа Child
>>>

Порядок вирішення методів

В Python лінеаризація також має назву MRO — "Method Resolution Order", порядок вирішення методів. Назва може трошки вводити в оману, тому що таким чином відбувається пошук не тільки методів, а й будь-яких атрибутів.

Лінеаризація для певного класа знаходиться в його спеціальному атрибуті __mro__:

>>> Child.__mro__
(<class '__main__.Child'>, <class '__main__.Base'>, <class '__main__.SuperBase'>, <class 'object'>)
>>>

Але частіше користуються методом класа, який повертає не кортеж, а одразу список:

>>> Child.mro()
[<class '__main__.Child'>, <class '__main__.Base'>, <class '__main__.SuperBase'>, <class 'object'>]
>>>

Ми отримали всю ієрархію успадкування, аж до класа object.

Перевірка об'єкта на належність класу

В Python є будована функція:

isinstance(obj, cls)

Повертає True якщо об'єкт obj є екземпляром класа cls або його суперкласів. Тобто перевірка відбувається по усій ієрархії успадкування:

>>> child_object = Child()
>>> isinstance(child_object, Child)
True
>>> isinstance(child_object, Base)
True
>>> isinstance(child_object, SuperBase)
True
>>> isinstance(child_object, object)
True
>>> isinstance(child_object, list)
False
>>>

Другим аргументом можна передати одразу декілька класів об'єднавши їх у кортеж. У цьому разі відбуватиметься перевірка належності об'єкта до ієрархій одразу декількох класів:

>>> isinstance(child_object, (Child, Base))
True
>>> isinstance(child_object, (Child, list))
True
>>> isinstance(child_object, (str, list))
False
>>> isinstance('text', (str, list))
True
>>> isinstance('text', (object, list))
True
>>>

Зауважте: функція isinstance() використовує лінеаризацію. Аналогічну перевірку можна виконати і так:

>>> type(child_object)
<class '__main__.Child'>
>>> type(child_object) in Child.mro()
True
>>>
Back to top