Наследование в Python
Наследование позволяет объявить класс, который дублирует функциональность уже существующего класса. С помощью этой концепции вы сможете расширить возможности своего класса.
Наследование — одна из концепций объектно-ориентированного программирования (ООП).
Как было сказано выше, наследование позволяет объявить класс, который либо не отличается от существующего, либо содержит минимальные изменения. Новый класс называется дочерним, а тот, у которого он наследует функционал — родительским.
Синтаксис
class BaseClass:
Тело родительского класса
class DerivedClass(BaseClass):
Тело дочернего класса
Особенность наследования заключается в том, что оно позволяет не просто создать дубликат класса, но и расширить его функционал. Это очень полезно, потому что наследование позволяет повторно использовать уже написанный код.
Пример использования наследования
Полигон — замкнутая геометрическая фигура. У полигона 3 и более сторон.
Давайте объявим класс Polygon
:
class Polygon:
def __init__(self, no_of_sides):
self.n = no_of_sides
self.sides = [0 for i in range(no_of_sides)]
def inputSides(self):
self.sides = [float(input("Введите сторону " + str(i+1)+ " : ")) for i in range(self.n)]
def dispSides(self):
for i in range(self.n):
print("Сторона", i+1, " — ", self.sides[i])
В этом классе объявлено несколько переменных. Одна хранит количество сторон — n
. Вторая, sides
— это список, в нём находятся размеры сторон.
Метод inputSides()
принимает размер каждой стороны, а dispSides()
выводит их на экран.
Треугольник — это полигон с 3 сторонами. Теперь мы можем создать класс Triangle
, который наследует весь функционал Polygon
. Благодаря этому все атрибуты класса Polygon
становятся доступны в Triangle
.
Так что нам не нужно объявлять все переменные и методы снова. Давайте создадим класс Triangle
:
class Triangle(Polygon):
def __init__(self):
Polygon.__init__(self,3)
def findArea(self):
a, b, c = self.sides
# Вычисляем полупериметр
s = (a + b + c) / 2
area = (s*(s-a)*(s-b)*(s-c)) ** 0.5
print('Площадь треугольника равна %0.2f' %area)
В классе есть и собственный метод findArea()
. Он вычисляет площадь треугольника и выводит ее на экран. Попробуем запустить нашу программу:
>>> t = Triangle()
>>> t.inputSides()
Введите сторону 1 : 3
Введите сторону 2 : 5
Введите сторону 3 : 4
>>> t.dispSides()
Сторона 1 — 3.0
Сторона 2 — 5.0
Сторона 3 — 4.0
>>> t.findArea()
Площадь треугольника равна 6.
Как видите, мы не объявляли методы inputSides()
и dispSides()
в классе Triangle
. Но вот использовать их мы можем!
Если какой-либо атрибут не найдется в дочернем классе, Python пойдет искать в родительской. Этот поиск происходит рекурсивно, если родительский класс одного класса является дочерним для другого.
Переопределение методов
Стоит заметить, что в примере метод __init__()
был объявлен в обоих классах — и в Triangle
, и в Polygon
. Здесь и происходит переопределение классов. То есть, метод в дочернем классе переопределяет тот же самый метод из родительского класса. Это значит, что __init__()
в Triangle
становится предпочтительнее __init__()
в Polygon
.
При переопределении метода родительского класса нужно стремиться к его расширению, а не простому копированию. Это, например, происходит при вызове метода в родительском классе из дочернего (вызов Polygon.__init__()
из __init__()
в Triangle
).
Лучше всего использовать встроенную функцию super()
. Например, super().__init__(3)
эквивалентно вызову Polygon.__init__(self, 3)
. Старайтесь использовать именно этот способ.
Проверка наследования
Для проверки наследования можно использовать две функции: isinstance()
и issubclass()
.
Функция isinstance()
возвращает True
, если объект является экземпляром класса или других производных от него классов. Каждый класс в Python является дочерним для какого-либо базового класса.
>>> isinstance(t, Triangle)
True
>>> isinstance(t, Polygon)
True
>>> isinstance(t, int)
False
>>> isinstance(t, object)
True
subclass()
же используется для проверки, наследуется ли какой-либо класс от другого.
>>> issubclass(Polygon, Triangle)
False
>>> issubclass(Triangle, Polygon)
True
>>> issubclass(bool, int)
True