Typing.overload: примеры (PYTHON)
typing.overload: callableФункция typing.overload в Python
Декоратор typing.overload позволяет определять несколько сигнатур для одной функции или метода. Он используется для указания, что функция может принимать различные комбинации типов аргументов и возвращать разные типы в зависимости от входных данных. Этот декоратор не изменяет поведение функции во время выполнения, но предоставляет информацию для статических анализаторов типов и систем подсказок.
Основное применение - документирование сложных перегрузок функций в модулях, написанных на чистом Python, особенно когда логика выбора реализации основана на типах или количестве аргументов.
Декоратор не принимает параметров, кроме самой декорируемой функции. Все определения перегрузок должны быть оформлены с использованием @overload, а фактическая реализация - в финальной функции без этого декоратора.
Сигнатура использования выглядит как последовательность декорированных @overload определений с разными типами аргументов, за которыми следует одно недекорированное определение с реализацией. Возвращаемые значения указываются через аннотацию -> для каждого варианта перегрузки.
Основные примеры использования
Пример перегрузки функции для обработки разных типов аргументов:
from typing import overload, Union
@overload
def process(value: int) -> str: ...
@overload
def process(value: str) -> int: ...
def process(value: Union[int, str]) -> Union[str, int]:
if isinstance(value, int):
return str(value)
return len(value)
print(process(42)) # Возвращает строку
print(process("hello")) # Возвращает целое число'42' 5
Пример с различным количеством аргументов:
from typing import overload
@overload
def multiply(x: int) -> int: ...
@overload
def multiply(x: int, y: int) -> int: ...
def multiply(x: int, y: int = 1) -> int:
return x * y
print(multiply(5))
print(multiply(5, 3))5 15
Похожие возможности в Python
Одиночные аннотации типов - базовый способ указания типов для аргументов и возвращаемого значения. Подходит для простых функций с одной сигнатурой.
Union и Optional типы - позволяют указывать несколько допустимых типов для одного аргумента. Используются когда функция принимает разные типы, но имеет одинаковую логику обработки.
Protocol и структурная типизация - определяют интерфейсы на основе наличия методов. Применяются для создания гибких контрактов между компонентами.
Функции с использованием isinstance - проверка типов во время выполнения. Подходит когда логика функции существенно отличается для различных типов входных данных.
Аналоги в других языках программирования
TypeScript поддерживает перегрузку функций через несколько объявлений с одной реализацией:
function process(value: number): string;
function process(value: string): number;
function process(value: any): any {
if (typeof value === 'number') {
return value.toString();
}
return value.length;
}Java реализует перегрузку методов с разными параметрами в одной классе:
public class Processor {
public String process(Integer value) {
return value.toString();
}
public Integer process(String value) {
return value.length();
}
}C# поддерживает перегрузку методов с разными сигнатурами:
public class Processor {
public string Process(int value) => value.ToString();
public int Process(string value) => value.Length;
}Отличие Python в том, что @overload существует только для статической типизации и не влияет на выполнение кода.
Типичные ошибки использования
Отсутствие финальной реализации после декорированных overload определений:
from typing import overload
@overload
def example(x: int) -> str: ...
# Ошибка: нет реализации функции
example(10)TypeError: 'function' object is not callable
Несоответствие сигнатур перегрузок и реализации:
from typing import overload
@overload
def test(x: int) -> str: ...
@overload
def test(x: str) -> int: ...
# Реализация не соответствует сигнатурам перегрузок
def test(x: int) -> str:
return str(x)
# Вызов с строковым аргументом вызовет ошибкуИспользование overload как обычного декоратора выполнения:
@overload
def calculate(x: int) -> int:
return x * 2 # Код никогда не выполнитсяИзменения в последних версиях
В Python 3.11 улучшена поддержка перегрузок для generic-классов и методов. Добавлена лучшая интеграция с протоколами и callback-типами.
В Python 3.10 улучшена обработка Union типов в перегрузках и повышена точность вывода типов при использовании статических анализаторов.
Начиная с Python 3.8, typing модуль получил более стабильный API, а перегрузки стали лучше обрабатываться различными инструментами проверки типов.
Расширенные примеры применения
Перегрузка с использованием generic-типов:
from typing import overload, TypeVar, Sequence, List
T = TypeVar('T')
@overload
def first(seq: Sequence[T]) -> T: ...
@overload
def first(seq: Sequence[T], default: T) -> T: ...
def first(seq: Sequence[T], default: T = None) -> T:
try:
return seq[0]
except IndexError:
return default
print(first([1, 2, 3]))
print(first([], 0))1 0
Перегрузка для методов класса с различными условиями:
from typing import overload
class Converter:
@overload
def convert(self, value: int, base: int) -> str: ...
@overload
def convert(self, value: str) -> int: ...
def convert(self, value, base=10):
if isinstance(value, int):
return format(value, f'0{base}')
return int(value)
conv = Converter()
print(conv.convert(255, 16))
print(conv.convert("FF", 16))'ff' 255
Комбинирование перегрузок с аргументами по ключу:
from typing import overload, Literal
@overload
def create_element(
type: Literal["button"],
text: str
) -> str: ...
@overload
def create_element(
type: Literal["input"],
placeholder: str
) -> str: ...
def create_element(**kwargs):
if "text" in kwargs:
return f"<button>{kwargs['text']}</button>"
return f"<input placeholder='{kwargs['placeholder']}'>"
print(create_element(type="button", text="Click"))
print(create_element(type="input", placeholder="Enter text"))<button>Click</button> <input placeholder='Enter text'>