😎ovld - перегрузка функций по-человечески
👩💻 Наверняка любой из нас когда-то писал код по типу этого:
def process(x: str | int) -> None:
if isinstance(x, int):
do_for_int(x)
elif isinstance(x, str):
do_for_str(x)
🙈 А пишем мы так потому-что в Python из под коробки нет красивой и нормальной поддержки ad-hoc полиморфизма, аля перегрузки методов.
❓ Ad-hoc полиморфизм - это возможность вызывать одну и ту же функцию с разными типами данных, при этом для каждого типа вызывается своя реализация. Например в Java мы можем написать что-то такое и это будет работать:
public int add(int a, int b) { return a + b; }
public double add(double a, double b) { return a + b; }
public String add(String a) { return a; }
🆘 А что делать, если хочется такое в Python? Есть несколько вариантов:
1. В стандартной библиотеке есть есть functools.singledispatch и functools.singledispatchmethod, но корректно они работают только с 1 аргументом 🤬:
from functools import singledispatch
@singledispatch
def process(x: Any):
print(f"Общий случай: {x}")
@process.register
def _(x: str):
print(f"Строка: {x}")
@process.register
def _(x: str, y: int): # сработает, но и сломает предыдущий обработчик
print(f"{x=}, {y=}")
2. Одно время часто советовали multipledispatch, но у него ряд недостатков - его не любят IDE, тайпинги не поддерживает, да и вообще всё еще стремно выглядит ⚰️:
from multipledispatch import dispatch
@dispatch(int, int) # никаких тайп хинтов, только вот так
def add(x, y):
return x + y
@dispatch(object, object)
def add(x, y):
return f"{x} + {y}"
add(1, 2) # 3
add(1, 'hello') #'1 + hello'
3. А еще можно использовать ovld 😎. Что он умеет?
👩💻 Перегружает по тайп-хинтам
👩💻 Полноценно работает с IDE и автодополнением (правда с pyright у меня иногда случаются нюансы)
😎 Умеет нормально работать с вложенными аннотациями (аля list[tuple[str, int])
😈 Не требует регистрации базовой функции (как в singledispatch)
💨 да и работает достаточно быстро (хотя