Наследование в Python
Наследование — это механизм, который позволяет создать новый класс на основе существующего. Дочерний класс получает атрибуты и методы родительского класса, но может расширять и модифицировать эту функциональность.
Проще говоря, наследование представляет отношения типа "является" (is-a): собака является животным, легковой автомобиль является транспортным средством.
Зачем нужно наследование?
- 🔄 Повторное использование кода — избавляет от дублирования
- 🌲 Логические иерархии — отражает естественные отношения между объектами
- 🧩 Расширяемость — легко добавлять новую функциональность
- 🔄 Полиморфизм — использовать объекты разных классов единообразно
Простое наследование в Python
Создать класс-наследник в Python очень просто — нужно указать родительский класс в скобках:
# Базовый класс >>> class Animal: ... def __init__(self, name): ... self.name = name >>> def speak(self): ... return "Звук животного" # Дочерний класс >>> class Dog(Animal): # Dog наследуется от Animal ... def speak(self): # Переопределяем метод ... return f"{self.name} говорит: Гав!" # Создаем экземпляры >>> animal = Animal("Существо") >>> dog = Dog("Рекс") # Вызываем методы >>> print(animal.speak())
Звук животного>>> print(dog.speak()) # Вызывает переопределенный методРекс говорит: Гав!>>> print(dog.name) # Атрибут унаследован от родительского классаРекс
Вызов методов родительского класса с super()
Часто требуется расширить функциональность родительского метода, а не полностью заменить. Для этого используется функция super():
>>> class Vehicle: ... def __init__(self, brand): ... self.brand = brand >>> def info(self): ... return f"Транспорт марки {self.brand}" >>> class Car(Vehicle): ... def __init__(self, brand, model): ... super().__init__(brand) # Вызываем конструктор родителя ... self.model = model >>> def info(self): ... # Расширяем родительский метод ... return f"{super().info()}, модель {self.model}" # Создаем автомобиль >>> car = Car("Toyota", "Corolla") >>> print(car.info())
Транспорт марки Toyota, модель Corolla
Иерархии наследования
Наследование можно выстраивать в многоуровневые иерархии:
>>> class Animal: ... def eat(self): ... return "Животное ест" >>> class Mammal(Animal): ... def breathe(self): ... return "Дышит легкими" >>> class Dog(Mammal): ... def bark(self): ... return "Гав!" # Создаем собаку >>> dog = Dog() >>> print(dog.eat()) # Метод из Animal
Животное ест>>> print(dog.breathe()) # Метод из MammalДышит легкими>>> print(dog.bark()) # Метод из DogГав!
Проверка наследования: isinstance() и issubclass()
Python предоставляет полезные функции для проверки отношений наследования:
# Базовый класс - родитель в иерархии >>> class Vehicle: ... pass # Пустой класс для демонстрации наследования # Дочерние классы - наследуются от Vehicle >>> class Car(Vehicle): ... pass # Car является разновидностью Vehicle >>> class Bicycle(Vehicle): ... pass # Bicycle тоже является разновидностью Vehicle # Создаем объекты >>> car = Car() # Экземпляр класса Car >>> bicycle = Bicycle() # Экземпляр класса Bicycle # Проверяем тип объектов # car является экземпляром класса Car? >>> print(isinstance(car, Car))
True# car является экземпляром класса Vehicle (через наследование)? >>> print(isinstance(car, Vehicle))True# car является экземпляром класса Bicycle? >>> print(isinstance(car, Bicycle))False# Проверяем отношения между классами >>> print(issubclass(Car, Vehicle)) # Car является подклассом Vehicle?True>>> print(issubclass(Vehicle, Car)) # Vehicle является подклассом Car?False
Абстрактные классы
Абстрактные классы служат как шаблоны для создания других классов. Они содержат абстрактные методы, которые должны быть реализованы в подклассах:
>>> from abc import ABC, abstractmethod >>> class Shape(ABC): # Абстрактный класс ... @abstractmethod ... def area(self): ... pass >>> @abstractmethod ... def perimeter(self): ... pass >>> class Rectangle(Shape): ... def __init__(self, width, height): ... self.width = width ... self.height = height >>> def area(self): ... return self.width * self.height >>> def perimeter(self): ... return 2 * (self.width + self.height) # Попытка создать экземпляр абстрактного класса >>> try: ... shape = Shape() ... except TypeError as e: ... print(f"Ошибка: {e}")
Ошибка: Can't instantiate abstract class Shape with abstract methods area, perimeter# Создание экземпляра конкретного класса >>> rect = Rectangle(5, 3) >>> print(f"Площадь: {rect.area()}")Площадь: 15>>> print(f"Периметр: {rect.perimeter()}")Периметр: 16
Множественное наследование
Python поддерживает множественное наследование, когда класс наследуется от нескольких родителей:
>>> class Flying: ... def fly(self): ... return "Я могу летать!" >>> class Swimming: ... def swim(self): ... return "Я могу плавать!" # Множественное наследование >>> class Duck(Flying, Swimming): ... def sound(self): ... return "Кря!" # Создаем утку >>> duck = Duck() >>> print(duck.fly())
Я могу летать!>>> print(duck.swim())Я могу плавать!>>> print(duck.sound())Кря!
Порядок разрешения методов (MRO)
При множественном наследовании важно знать, в каком порядке Python ищет методы в классах. Этот порядок называется Method Resolution Order (MRO):
>>> class A: ... def method(self): ... return "A" >>> class B(A): ... def method(self): ... return "B" >>> class C(A): ... def method(self): ... return "C" >>> class D(B, C): ... pass # Проверяем MRO класса D >>> print(D.__mro__)
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)# Создаем объект и вызываем метод >>> d = D() >>> print(d.method()) # Будет вызван метод из B, так как B стоит перед CB
Проверка понимания
Что произойдет при вызове метода из дочернего класса, который не переопределяет этот метод родительского класса?