Спадкування дозволяє створити новий клас на основі існуючого класу. Новий клас, що створюється, називається підкласом (дочірній або похідний клас), а існуючий клас, від якого отримано дочірній клас, називається суперкласом (батьківський або базовий клас).
Підклас та суперклас в Python
Синтаксис спадкування в Python:
|
1 2 3 4 5 6 7 8 |
# Визначаємо суперклас class super_class: # Атрибути та методи суперкласу # Спадкування class sub_class(super_class): # Атрибути та метод super_class # Атрибути та метод sub_class |
Тут ми успадковуємо клас sub_class від класу super_class.
Розглянемо приклад на практиці:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class Animal: # Атрибут та метод батьківського класу name = "" def eat(self): print("I can eat") # Успадковуємо від класу Animal class Dog(Animal): # Новий метод у дочірньому класі def display(self): # Доступ до атрибута name батьківського класу за допомогою self print("My name is ", self.name) # Створюємо об'єкт дочірнього класу labrador = Dog() # Отримуємо доступ до атрибута та методу батьківського класу labrador.name = "Rohu" labrador.eat() # Викликаємо метод дочірнього класу labrador.display() |
Результат:
I can eat
My name is Rohu
Тут ми створили дочірній клас Dog з батьківського класу Animal. Зверніть увагу на наступний код:
|
1 2 |
labrador.name = "Rohu" labrador.eat() |
Тут ми використовуємо labrador (об’єкт класу Dog) для доступу до name та eat() класу Animal. Це можливо тому, що дочірній клас успадковує всі атрибути та методи батьківського класу. Крім того, ми отримали доступ до атрибута name всередині методу класу Dog, використовуючи self.
Відносини в успадкуванні
В Python успадкування — це відносини типу is-a (є). Ми використовуємо спадкування лише в тому випадку, коли між двома класами існує зв’язок типу “є”. Наприклад:
Автомобіль є Транспортним засобом
Яблуко є Фруктом
Кішка є Твариною
Автомобіль може успадковуватись від Транспортний засіб, Яблуко може успадковуватися від Фрукт і так далі.
Розглянемо ще один приклад спадкування в Python. Багатокутник — це замкнута фігура з 3 або більше сторонами. Припустимо, у нас є клас Polygon, визначений наступним чином:
|
1 2 3 4 5 6 7 8 9 10 11 |
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("Enter side "+str(i+1)+" : ")) for i in range(self.n)] def dispSides(self): for i in range(self.n): print("Side",i+1,"is",self.sides[i]) |
Цей клас має змінні для зберігання кількості (n) та довжини (у вигляді списку під назвою sides) кожної зі сторін багатокутника.
Метод inputSides() приймає довжину кожної сторони.
Метод dispSides() відображає довжини цих сторін.
Трикутник — це багатокутник із трьома сторонами. Тому ми можемо створити клас Triangle, який успадковується від класу Polygon. Це зробить усі атрибути класу Polygon доступними для класу Triangle. Нам не потрібно визначати атрибути та методи знову. Наприклад:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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('The area of the triangle is %0.2f' %area) |
Однак у класі Triangle є новий метод findArea() для обчислення та виводу на екран площі трикутника.
Тепер подивимося на повний робочий код програми:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
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("Enter side "+str(i+1)+" : ")) for i in range(self.n)] # Метод для виведення довжини кожної зі сторін багатокутника def dispSides(self): for i in range(self.n): print("Side",i+1,"is",self.sides[i]) class Triangle(Polygon): # Ініціалізація кількості сторін трикутника (3) шляхом виклику методу __init__() класу 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('The area of the triangle is %0.2f' %area) # Створюємо об'єкт класу Triangle t = Triangle() # Пропонуємо користувачеві ввести довжини сторін трикутника t.inputSides() # Виводимо довжини сторін трикутника t.dispSides() # Обчислюємо та виводимо площу трикутника t.findArea() |
Результат:
Enter side 1 : 3
Enter side 2 : 5
Enter side 3 : 4
Side 1 is 3.0
Side 2 is 5.0
Side 3 is 4.0
The area of the triangle is 6.00
Тут ми бачимо, що хоча ми не визначили методи типу inputSides() або dispSides() для класу Triangle окремо, ми змогли їх використати.
Якщо атрибут не знайдено у самому класі, пошук починається у батьківському класі. Це повторюється рекурсивно, якщо батьківський клас сам успадковується з інших класів.
Перевизначення методів у спадкуванні
З попереднього прикладу ми бачимо, що об’єкт підкласу може отримати доступ до методу суперкласу.
Але якщо один і той самий метод присутній і в суперкласі, і в підкласі?
У цьому випадку метод у підкласі перевизначає метод у суперкласі. Ця концепція відома як перевизначення методів у Python. Наприклад:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class Animal: # Атрибути та метод суперкласу name = "" def eat(self): print("I can eat") # Успадковуємо від класу Animal class Dog(Animal): # Перевизначаємо метод eat() def eat(self): print("I like to eat bones") # Створюємо об'єкт підкласу labrador = Dog() # Викликаємо метод eat() через об'єкт класу Dog labrador.eat() |
Результат:
I like to eat bones
Тут один і той самий метод eat() присутній як у класі Dog, так і в класі Animal. Коли ми викликаємо метод eat(), використовуючи об’єкт підкласу Dog, викликається метод класу Dog. Це відбувається тому, що метод eat() підкласу Dog перевизначає той самий метод суперкласу Animal.
Метод super() в спадкуванні
Раніше ми бачили, що метод з одним і тим самим ім’ям у підкласі перевизначає метод у суперкласі. Однак, якщо нам потрібно отримати доступ до методу суперкласу підкласу, ми можемо скористатися додатковим методом super(). Наприклад:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class Animal: # Атрибути та метод батьківського класу name = "" def eat(self): print("I can eat") # Успадковуємо від класу Animal class Dog(Animal): # Перевизначаємо метод eat() def eat(self): # Викликаємо метод eat() батьківського класу за допомогою додаткового методу super() super().eat() print("I like to eat bones") # Створюємо об'єкт дочірнього класу labrador = Dog() labrador.eat() |
Результат:
I can eat
I like to eat bones
Тут метод eat() дочірнього класу Dog перевизначає цей самий метод батьківського класу Animal.
Всередині класу Dog ми використали наступний рядок коду, щоб викликати метод eat() батьківського класу Animal з дочірнього класу Dog:
|
1 2 |
# Викликаємо метод eat() батьківського класу за допомогою додаткового методу super() super().eat() |
Таким чином, коли ми викликаємо метод eat(), використовуючи об’єкт labrador:
|
1 |
labrador.eat() |
Виконується як перевизначена версія методу eat() у дочірньому класі, так і версія методу eat() батьківського класу.
Яка користь від спадкування в Python?
Оскільки дочірній клас може успадковувати функціонал батьківського класу, це дозволяє повторно використовувати код без його дублювання.
Розробивши функціонал, ми можемо просто його успадкувати. Не потрібно наново винаходити велосипед. Це робить код чистішим і простішим у підтримці.
Оскільки в дочірній клас можна додавати власний функціонал, то можна успадковувати лише потрібний функціонал батьківського класу, а все інше дописати в конкретному (дочірньому) класі.

(18 оцінок, середня: 4,83 з 5)