Ответ
В контексте Python под полиморфизмом функций понимают способность одной функции или оператора работать с объектами разных типов. Основные формы, которые можно встретить:
1. Ad-hoc полиморфизм (Перегрузка)
Это возможность определять несколько версий функции для разных типов аргументов. В Python это реализуется не через одинаковые имена функций (как в C++ или Java), а с помощью декоратора @singledispatch из модуля functools.
Пример: Создадим функцию format_value, которая по-разному форматирует целые числа и строки.
from functools import singledispatch
@singledispatch
def format_value(value):
"""Базовая реализация по умолчанию."""
return str(value)
@format_value.register(int)
def _(value):
"""Реализация для целых чисел (int)."""
return f"Integer: {value}"
@format_value.register(str)
def _(value):
"""Реализация для строк (str)."""
return f'String: "{value}"'
print(format_value(123)) # Вывод: Integer: 123
print(format_value("hello")) # Вывод: String: "hello"
print(format_value([1, 2, 3])) # Вывод: [1, 2, 3] (используется базовая реализация)
2. Параметрический полиморфизм (через утиную типизацию)
Это способность функции выполняться одинаково для любого типа данных, который поддерживает необходимые ей операции. В Python это достигается за счет утиной типизации (duck typing): "если что-то крякает как утка и плавает как утка, то это утка". Тип объекта не важен, важны лишь его методы и атрибуты.
Пример: Встроенная функция len() работает с любым объектом, у которого есть метод __len__().
# len() работает со строкой, списком и словарем
print(len("Python")) # 6
print(len([1, 2, 3, 4])) # 4
print(len({"a": 1, "b": 2})) # 2
# Создадим свой класс с методом __len__
class Order:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
my_order = Order(["apple", "banana", "orange"])
print(len(my_order)) # 3, len() успешно работает с нашим объектом Ответ 18+ 🔞
А, ну вот, опять про этот ваш полиморфизм, блядь. Сидят, умные такие, терминами кидаются. А на деле всё просто, как три копейки, ёпта.
Смотри, есть у тебя функция. И вот эта самая функция, хитрая жопа такая, может работать не с одним типом данных, а с кучей разных. Это и есть полиморфизм, если по-простому. В Питоне он бывает двух основных видов, и первый — это как бы «перегрузка», только по-питонячьи, блядь.
1. Полиморфизм «на выбор» (Ad-hoc)
В других языках ты можешь десять функций с одним именем написать, только аргументы разные. В Питоне так нельзя, он тебе сразу скажет: «Иди нахуй, имя уже занято». Но выход есть, ёпта! Декоратор @singledispatch из functools. Он как швейцар в дорогом клубе: смотрит на тип гостя (аргумента) и пускает его к нужной реализации.
Вот смотри, как это выглядит. Делаем функцию format_value, которая по-разному будет выёбываться с числами и строками.
from functools import singledispatch
@singledispatch
def format_value(value):
"""Базовая реализация по умолчанию."""
return str(value)
@format_value.register(int)
def _(value):
"""Реализация для целых чисел (int)."""
return f"Integer: {value}"
@format_value.register(str)
def _(value):
"""Реализация для строк (str)."""
return f'String: "{value}"'
print(format_value(123)) # Вывод: Integer: 123
print(format_value("hello")) # Вывод: String: "hello"
print(format_value([1, 2, 3])) # Вывод: [1, 2, 3] (используется базовая реализация)
Видишь? Кинул ей число — она тебе «Integer» вывела. Кинул строку — «String». А кинул список, на который регистрации нет, — она просто в строку превратила, по дефолту. Удобно, блядь, не надо городить кучу if isinstance(...).
2. Полиморфизм «по-утиному» (Параметрический)
А вот это, блядь, моя любимая тема. Утиная типизация! Принцип простой, как палка: «Если что-то крякает как утка и плавает как утка, то это утка». Нам похуй на тип объекта, нам важно, чтобы у него был нужный метод. Если есть — работаем. Нет — получи по ебалу с AttributeError.
Классический пример — встроенная функция len(). Ей абсолютно насрать, что ты ей передаёшь: строку, список, свой класс. Лишь бы у объекта был метод __len__(). Она его вызовет и всё.
# len() работает со строкой, списком и словарем
print(len("Python")) # 6
print(len([1, 2, 3, 4])) # 4
print(len({"a": 1, "b": 2})) # 2
# Создадим свой класс с методом __len__
class Order:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
my_order = Order(["apple", "banana", "orange"])
print(len(my_order)) # 3, len() успешно работает с нашим объектом
Вот и вся магия, ёпта. Не нужно никого наследовать от какого-то общего абстрактного «Измеримого». Просто сделал метод __len__ — и ты уже утка в глазах функции len(). Пиздец как гибко и просто. Это и есть сила Питона, блядь, в этом вся его прелесть.