Поліморфізм

Модуль 1: Python Core
Рівень 9 , Лекція 7
Відкрита

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

Якщо передані неправильні типи даних, можна вивести інструкцію або навіть посилання на документацію в інтернеті — це теж дуже популярне рішення.

Коментарі (1)
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ
Дмитро Рівень 30
10 листопада 2025
Який інтерфейс? 😳