Сообщить об ошибке.

Наследование классов в Python.

Классы в языке Python поддерживают наследование классов, что позволяет создавать новые классы с расширенным и/или измененным функционалом базового класса. Новый класс, созданный на основе базового класса - называется производный класс (derived class) или просто подкласс.

Подкласс наследует атрибуты и методы из родительского класса. Он так же может переопределять (override) методы родительского класса. Если подкласс не определяет свой конструктор __init__, то он наследует конструктор родительского класса по умолчанию.

Синтаксис определения производного (дочернего) класса выглядит следующим образом:

class DerivedClassName(BaseClassName):
    <statement-1>
    .
    <statement-N>

Имя BaseClassName должно быть определено в области, содержащей определение производного класса. Вместо имени базового класса допускаются и другие произвольные выражения. Это может быть полезно, например, когда базовый класс определен в другом модуле:

class DerivedClassName(modname.BaseClassName):
    <statement-1>
    .
    <statement-N>

Выполнение определения производного класса DerivedClassName происходит так же, как и для базового класса BaseClassName. Когда объект класса создан, базовый класс BaseClassName запоминается. Это используется для разрешения ссылок на атрибуты. Если запрошенный атрибут не найден в классе DerivedClassName, поиск переходит к поиску в базовом классе BaseClassName. Это правило применяется рекурсивно, если сам базовый класс является производным от какого-либо другого класса.

В создании экземпляров производных классов нет ничего особенного. Выражение a = DerivedClassName() создает новый экземпляр класса. Ссылки на методы разрешаются следующим образом: поиск соответствующего атрибута данных класса осуществляется по цепочке базовых классов, если это необходимо. Ссылка на метод класса будет действительна, если поиск обнаружил функциональный объект.

Производные классы DerivedClassName могут переопределять методы своих базовых классов BaseClassName. Поскольку методы не имеют особых привилегий при вызове других методов того же объекта, метод базового класса, который вызывает другой метод, определенный в том же базовом классе, может в конечном итоге вызвать метод производного класса, который переопределяет его. Для программистов C++ - все методы в Python фактически являются виртуальными.

Переопределяющий метод в производном классе может фактически расширить, а не просто заменить метод базового класса с тем же именем. Существует простой способ вызвать метод базового класса напрямую: просто вызовите BaseClassName.methodname(self, arguments). Это иногда полезно и для "клиентов". Обратите внимание, что это работает только в том случае, если базовый класс доступен как имя базового класса BaseClassName в глобальной области видимости.

Python имеет две встроенные функции, которые работают с наследованием:

  • Используйте isinstance() для проверки типа экземпляра класса: isinstance(obj, int) будет истинным True только в том случае, если obj.__class__ равен int или класс является производным от класса int.

  • Используйте issubclass() для проверки наследования классов: issubclass(bool, int) является истинным, так как bool является подклассом int(). Однако issubclass(float, int) является ложным False, так как float не является подклассом int.

Примеры использования переопределения методов.

class One:
    def __init__(self, name):
        self.name = name

    def talk(self):
        return f'Меня зовут {self.name}'

    def say(self):
        return f'Привет {self.name}'


class Two(One):
    # декорируем метод
    def say(self):
        x = One.say(self)
        return f'{x} !!!'


class Three(One):
    # переопределяем метод
    def say(self, word):
        return f'{word} {self.name}...'

one = One('Андрей')
two = Two('Юра')
three = Three('Аня')

Результат:

print(f'class {One.__name__}:')
print(one.talk())
print(one.say())
# class One:
# Меня зовут Андрей
# Привет Андрей

print(f'class {Two.__name__}:')
print(two.talk())
print(two.say())
print('Two is subclass One:', issubclass(Two, One))
# class Two:
# Меня зовут Юра
# Привет Юра !!!
# Two is subclass One: True

print(f'class {Three.__name__}:')
print(three.talk())
print(three.say('Пока'))
print('Three is subclass One:', issubclass(Three, One))
# class Three:
# Меня зовут Аня
# Пока Аня...
# Three is subclass One: True

print('Three is subclass Two:', issubclass(Three, Two))
# Three is subclass Two: False