8.1 Поліморфізм
Поліморфізм — одна з основних концепцій об'єктно-орієнтованого програмування (ООП), яка дозволяє об'єктам різних класів використовувати один і той же інтерфейс.
У Python поліморфізм досягається через динамічну типізацію та наслідування. Важливим аспектом поліморфізму є перевантаження методів і заміщення методів базового класу методами класу-нащадка.
Основні концепції поліморфізму:
Єдиний інтерфейс для різних об'єктів:
Поліморфізм дозволяє використовувати єдиний інтерфейс для об'єктів різних класів, які можуть мати різну реалізацію методів.
Динамічна типізація:
У Python тип змінної визначається під час виконання, що дозволяє функції працювати з об'єктами будь-якого класу, якщо вони підтримують вимаганий інтерфейс.
Наслідування:
Дозволяє створювати ієрархії класів, де підкласи наслідують властивості та методи базового класу, але можуть перевизначати їх для своєї специфічної функціональності.
Приклади поліморфізму:
Простий приклад поліморфізму: всі три класи мають метод з іменем move(). Це значить, що ми можемо написати код, який буде одночасно працювати з цими об'єктами.
class Car:
def move(self):
pass
class Human:
def move(self):
pass
class Bird:
def move(self):
print("Кар!")
car = Car()
human = Human()
bird = Bird()
for it in [car, human, bird]:
it.move()
У даному випадку «загальним інтерфейсом» є ім'я методу, ну або його сигнатура, якщо метод має параметри.
8.2 Перевизначення методів
Поліморфізм часто використовується разом з наслідуванням для створення ієрархій класів, де базовий клас визначає загальний інтерфейс, а підкласи реалізують специфічні деталі.
class Employee:
def get_salary(self):
return 1000
class FullTimeEmployee(Employee):
def get_salary(self):
return 5000
class PartTimeEmployee(Employee):
def get_salary(self):
return 3000
class Intern(Employee):
pass
def print_salary(employee):
print(employee.get_salary())
employees = [FullTimeEmployee(), PartTimeEmployee(), Intern()]
for employee in employees:
print_salary(employee)
Цей приклад схожий на попередній, але має важливу відмінність — наші класи не зобов'язані мати метод get_salary, адже він завжди є у базового класу. Тепер «загальним інтерфейсом» всіх класів є не просто метод get_salary(), а саме клас Employee зі всіма його методами та атрибутами.
8.3 Виклик методів класу-нащадка
Подивіться уважніше на код нижче:
Ми викликаємо метод print_salary(), який є тільки у базового класу Employee, а він вже з базового класу викликає інший метод базового класу — get_salary(). Які зарплати будуть виведені на екран?
class Employee:
def print_salary(self):
salary = self.get_salary()
print(salary)
def get_salary(self):
return 1000
class FullTimeEmployee(Employee):
def get_salary(self):
return 5000
class PartTimeEmployee(Employee):
def get_salary(self):
return 3000
class Intern(Employee):
pass
employees = [FullTimeEmployee(), PartTimeEmployee(), Intern()]
for employee in employees:
employee.print_salary()
Важливо! Прочитайте те, що написано нижче — це важливо.
Якщо ми викличемо метод print_salary(), наприклад, у класу FullTimeEmployee, то викликатиметься метод базового класу, так як у самого класу такий метод не оголошений.
Але ось цей метод print_salary() буде викликати метод get_salary() у об'єкта self, який має тип FullTimeEmployee, а не Employee. Тому викликатиметься саме метод get_salary() з класу FullTimeEmployee!
Більше того, клас FullTimeEmployee може викликати метод get_salary() базового класу для своїх потреб. Наприклад, ми хочемо розраховувати зарплату у відсотках від базової ставки:
class FullTimeEmployee(Employee):
def get_salary(self):
base_salary = super().get_salary()
return base_salary * 5
# 500%
class PartTimeEmployee(Employee):
def get_salary(self):
base_salary = super().get_salary()
return base_salary * 3 # 300%
8.4 Перевантаження методів
Перевантаження методів (method overloading) в Python — це здатність створювати декілька методів з однаковим ім'ям, але різними параметрами. Проте, в чистому вигляді перевантаження методів не підтримується в Python, як це робиться в інших мовах (наприклад, C++ або Java).
У Python можна імітувати перевантаження методів через використання аргументів за замовчуванням, *args і **kwargs.
Приклади перевантаження методів
Ми можемо реалізувати функцію, яка матиме різну поведінку в залежності від кількості переданих аргументів. Зробити це можна різними способами, наприклад, так:
class Example:
def display(self, a=None, b=None):
if a is not None and b is not None: print(a, b)
elif a is not None: print(a)
else: print("Немає аргументів")
obj = Example()
obj.display(1, 2) # Output: 1 2
obj.display(1) # Output: 1
obj.display() # Output: Немає аргументів
Приклад 2 — враховуємо тип переданих даних
Також можна врахувати тип переданих даних — просто зробити перевірку типу:
class Example:
def mod(self, a, b):
if type(a) == int and type(b) == int: print(a % b)
elif type(a) == float or type(b) == float: print(round(a / b))
else: print("Інструкція: a та b повинні бути int або float")
obj = Example()
obj.mod(5, 2) # Output: 1
obj.mod(5.0, 2) # Output: 2
obj.mod("5", 2) # Output: Інструкція: a та b повинні бути int або float
Якщо передані неправильні типи даних, можна вивести інструкцію або навіть посилання на документацію в інтернеті — це теж дуже популярне рішення.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ