Наследование — это один из ключевых концептов объектно-ориентированного программирования (ООП), который позволяет создавать новые классы на основе уже существующих. При этом новый класс, называемый потомком, унаследует все методы и атрибуты своего родительского класса. Этот подход позволяет сократить дублирование кода, сделать его более модульным и легко поддерживаемым.
Допустим, перед нами стоит задача описать работников организации. В нашей организации есть врачи и архитекторы, каждый из которых выполняет свою профессиональную функцию. Для этого были созданы два отдельных класса:
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 . |
Итог | Наследование позволяет структурировать код, избавляясь от дублирования и повторения. Добавление новой профессии происходит без необходимости переписывать общие методы, так как они будут унаследованы автоматически. Это упрощает расширение и поддержку кода. |
Принцип наследования позволяет легко и эффективно организовать код, убрав дублирование и сделав его более структурированным. Теперь, добавив новую профессию, нам не нужно вручную дублировать методы — они будут автоматически унаследованы из родительского класса.