Наследование — один из ключевых принципов ООП, позволяющий создавать новый класс (дочерний) на основе существующего (родительского). Дочерний класс наследует атрибуты и методы родительского класса, что способствует повторному использованию кода и созданию иерархии классов.
Отношение между классами при наследовании часто описывается как “является” (is-a). Например, “Собака является Животным”.
4.1. Базовый Синтаксис
Для указания наследования имя родительского класса указывается в скобках после имени дочернего класса.
# Родительский (базовый) класс
class Animal:
def __init__(self, name):
self.name = name
print(f"Создано животное: {self.name}")
def speak(self):
raise NotImplementedError("Дочерний класс должен реализовать этот метод")
def eat(self):
print(f"{self.name} ест.")
# Дочерний класс, наследующий от Animal
class Dog(Animal):
def speak(self): # Переопределяем метод speak
print(f"{self.name} говорит Гав!")
# Другой дочерний класс
class Cat(Animal):
def speak(self): # Переопределяем метод speak
print(f"{self.name} говорит Мяу!")
def purr(self): # Добавляем свой уникальный метод
print(f"{self.name} мурлычет.")
# Создаем объекты дочерних классов
my_dog = Dog("Рекс") # Выведет: Создано животное: Рекс
my_cat = Cat("Барсик") # Выведет: Создано животное: Барсик
# Вызываем унаследованный метод eat
my_dog.eat() # Рекс ест.
my_cat.eat() # Барсик ест.
# Вызываем переопределенный метод speak
my_dog.speak() # Рекс говорит Гав!
my_cat.speak() # Барсик говорит Мяу!
# Вызываем собственный метод Cat
my_cat.purr() # Барсик мурлычет.
# my_dog.purr() # AttributeError: 'Dog' object has no attribute 'purr'
4.2. Функция super()
Функция super()
позволяет дочернему классу вызывать методы родительского класса. Это особенно полезно, когда нужно расширить, а не полностью заменить, функциональность родительского метода (например, __init__
).
class Employee:
def __init__(self, first, last, pay):
self.first = first
self.last = last
self.pay = pay
self.email = f"{first}.{last}@company.com"
print(f"Создан сотрудник {self.first} {self.last}")
class Developer(Employee):
def __init__(self, first, last, pay, prog_lang):
# Вызываем __init__ родительского класса (Employee)
super().__init__(first, last, pay)
# Добавляем свой атрибут
self.prog_lang = prog_lang
print(f"Сотрудник {self.first} является разработчиком")
dev1 = Developer("Анна", "Петрова", 80000, "Python")
# Вывод:
# Создан сотрудник Анна Петрова
# Сотрудник Анна является разработчиком
print(dev1.email) # anna.petrova@company.com
print(dev1.prog_lang) # Python
4.3. Переопределение Методов (Method Overriding)
Дочерний класс может предоставить свою собственную реализацию метода, который уже существует в родительском классе. Это называется переопределением. Как показано в первом примере, классы Dog
и Cat
переопределили метод speak
класса Animal
.
Если нужно вызвать и родительскую версию метода внутри переопределенного, используется super().method_name()
.
class Parent:
def greet(self):
print("Привет от родителя!")
class Child(Parent):
def greet(self):
super().greet() # Вызываем родительский метод
print("... и привет от ребенка!")
child_obj = Child()
child_obj.greet()
# Вывод:
# Привет от родителя!
# ... и привет от ребенка!
4.4. Множественное Наследование
Python поддерживает множественное наследование, когда класс может наследовать от нескольких родительских классов. Родительские классы перечисляются через запятую в скобках.
class Swimmer:
def swim(self):
print("Плавает")
class Flyer:
def fly(self):
print("Летает")
# Наследует от обоих классов
class Duck(Swimmer, Flyer):
def quack(self):
print("Крякает")
duck = Duck()
duck.swim() # Плавает
duck.fly() # Летает
duck.quack() # Крякает
MRO (Method Resolution Order - Порядок разрешения методов): При множественном наследовании Python определяет порядок, в котором ищутся методы и атрибуты в иерархии классов. Этот порядок можно посмотреть с помощью атрибута __mro__
или метода mro()
.
print(Duck.__mro__)
# Вывод (примерный):
# (<class '__main__.Duck'>, <class '__main__.Swimmer'>, <class '__main__.Flyer'>, <class 'object'>)
Это означает, что Python сначала ищет метод в Duck
, затем в Swimmer
, затем в Flyer
, и в последнюю очередь в базовом классе object
.
Осторожно: Множественное наследование может усложнить код и привести к проблемам (например, “проблема ромба” - diamond problem), если не использовать его аккуратно. Часто предпочтительнее использовать композицию (когда объект содержит экземпляры других классов) или миксины (классы, предназначенные для добавления функциональности другим классам через наследование).
〰〰〰 𓆝 𓆟 𓆞 𓆝 𓆟 𓆝 𓆟 𓆞 〰〰〰