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("No arguments")
obj = Example()
obj.display(1, 2) # Output: 1 2
obj.display(1) # Output: 1
obj.display() # Output: No arguments
Также можно учесть тип переданных данных — просто сделать проверку типа:
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("Help instruction: a and b should be int or float")
obj = Example()
obj.mod(5, 2) # Output: 1
obj.mod(5.0, 2) # Output: 2
obj.mod("5", 2) # Output: Help instruction: a and b should be int or float
Если переданы неправильные типы данных, можно вывести инструкцию или даже ссылку на документацию в интернете — это тоже очень популярное решение.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ