Принцип наследования в объектно-ориентированном программировании

Наследование — это один из ключевых концептов объектно-ориентированного программирования (ООП), который позволяет создавать новые классы на основе уже существующих. При этом новый класс, называемый потомком, унаследует все методы и атрибуты своего родительского класса. Этот подход позволяет сократить дублирование кода, сделать его более модульным и легко поддерживаемым.


Классы без использования наследования

Допустим, перед нами стоит задача описать работников организации. В нашей организации есть врачи и архитекторы, каждый из которых выполняет свою профессиональную функцию. Для этого были созданы два отдельных класса:

class Doctor:
    def can_cure(self):
        print("Я могу лечить")

class Architect:
    def can_build(self):
        print("Я могу строить")

Экземпляр класса Doctor может вызывать метод .can_cure(), а экземпляр класса Architect — метод .can_build(). Каждый из этих классов содержит только свою функциональность.

Теперь представим, что у всех работников есть общая способность — ходить, которую мы хотим описать с помощью метода .can_walk(). Без наследования нам пришлось бы добавить этот метод в оба класса:

class Doctor:
    def can_cure(self):
        print("Я могу лечить")

    def can_walk(self):
        print("Я могу ходить")

class Architect:
    def can_build(self):
        print("Я могу строить")

    def can_walk(self):
        print("Я могу ходить")

Как только нам потребуется добавить ещё какую-то общую способность, например, спать, код усложнится, и мы снова будем дублировать его:

class Doctor:
    def can_sleep(self):
        print("Я могу спать")

    def can_cure(self):
        print("Я могу лечить")

    def can_walk(self):
        print("Я могу ходить")

class Architect:
    def can_sleep(self):
        print("Я могу спать")

    def can_build(self):
        print("Я могу строить")

    def can_walk(self):
        print("Я могу ходить")

Этот подход неэффективен, так как для каждого нового класса (например, для Teacher) придётся копировать все общие методы:

class Teacher:
    def can_sleep(self):
        print("Я могу спать")

    def can_teach(self):
        print("Я могу учить")

    def can_walk(self):
        print("Я могу ходить")


Наследование как решение

Чтобы избежать дублирования, можно создать базовый класс, который будет содержать общие методы для всех работников. Например, все эти профессии относятся к категории людей, и можно создать класс Person с методами, которые описывают общие для всех людей действия.

class Person:
    def can_sleep(self):
        print("Я могу спать")

    def can_walk(self):
        print("Я могу ходить")

Теперь создадим дочерние классы для каждой профессии, которые будут наследовать методы класса Person:

class Doctor(Person):
    def can_cure(self):
        print("Я могу лечить")

class Architect(Person):
    def can_build(self):
        print("Я могу строить")

class Teacher(Person):
    def can_teach(self):
        print("Я могу учить")

Схематично наследование между классами можно представить так:

Person
  |
  +-- Doctor
  |
  +-- Architect
  |
  +-- Teacher

Теперь каждый из потомков (Doctor, Architect, Teacher) будет обладать методами .can_walk() и .can_sleep() благодаря наследованию от родительского класса Person.


Пример расширения иерархии

Иерархия классов может быть расширена для создания более специализированных классов. Например, для врача можно создать более конкретный класс, представляющий ортопеда:

class Orthopedist(Doctor):
    def can_fix_bones(self):
        print("Я могу лечить кости")

Теперь ортопед не только может лечить, но и обладает специализированной способностью.

Иерархия классов теперь будет выглядеть так:

Person
  |
  +-- Doctor
        |
        +-- Orthopedist
  |
  +-- Architect
  |
  +-- Teacher


Проверка классов с помощью issubclass() и isinstance()

Иногда необходимо проверить, является ли один класс потомком другого. Для этого используется функция issubclass(), которая возвращает True, если первый класс является потомком второго:

print(issubclass(Doctor, Person))   # True
print(issubclass(Orthopedist, Doctor))   # True
print(issubclass(Architect, Person))   # True
print(issubclass(Architect, Doctor))   # False

Также, чтобы проверить, является ли объект экземпляром определённого класса (или его потомков), можно использовать функцию isinstance():

p = Person()
d = Doctor()
ort = Orthopedist()
t = Teacher()

print(isinstance(d, Doctor))    # True
print(isinstance(d, Person))    # True
print(isinstance(ort, Orthopedist))   # True
print(isinstance(ort, Doctor))    # True
print(isinstance(ort, Person))    # True
print(isinstance(t, Architect))   # False

 

ТемаОписание
ЗадачаОписать работников организации, у каждого из которых своя профессиональная функция.
Классы без наследованияСозданы два класса: Doctor и Architect. Каждый из них содержит свои методы: .can_cure() для врача и .can_build() для архитектора. Однако у всех работников есть общая способность — ходить, которую описывает метод .can_walk(). Без наследования каждый класс должен отдельно содержать этот метод, что приводит к дублированию кода. Добавление других общих методов, например .can_sleep(), ещё сильнее усложнит структуру.
Наследование как решениеДля избежания дублирования создаётся базовый класс Person, который содержит общие методы для всех работников. Дочерние классы (врачи, архитекторы, учителя) наследуют методы класса Person и добавляют свои специфические методы. Например, Doctor будет содержать метод .can_cure(), а Architect — метод .can_build().
Пример расширения иерархииИерархию классов можно расширить. Например, можно создать класс Orthopedist, который наследует функционал класса Doctor, но добавляет специализированный метод .can_fix_bones(). Теперь ортопед может лечить кости, при этом он унаследует все возможности врача.
issubclass()Используется для проверки, является ли один класс потомком другого. Например, issubclass(Doctor, Person) вернёт True, так как Doctor наследует Person. Аналогично, issubclass(Orthopedist, Doctor) вернёт True, поскольку ортопед наследует функционал врача.
isinstance()Используется для проверки, является ли объект экземпляром определённого класса (или его потомков). Например, если создать объект d = Doctor(), то isinstance(d, Doctor) вернёт True, так как d — это экземпляр класса Doctor. Аналогично isinstance(d, Person) также вернёт True, так как класс Doctor наследует класс Person.
ИтогНаследование позволяет структурировать код, избавляясь от дублирования и повторения. Добавление новой профессии происходит без необходимости переписывать общие методы, так как они будут унаследованы автоматически. Это упрощает расширение и поддержку кода.

 

Принцип наследования позволяет легко и эффективно организовать код, убрав дублирование и сделав его более структурированным. Теперь, добавив новую профессию, нам не нужно вручную дублировать методы — они будут автоматически унаследованы из родительского класса.

Перейти к следующему шагу

Комментарии