Аннотация типов для *args и **kwargs в Python
Пройдите тест, узнайте какой профессии подходите
Быстрый ответ
Чтобы указать типы элементов в *args
, используйте Type
для элементов одного типа и конструкцию Union[Type1, Type2]
, если элементы могут быть разных типов. Для **kwargs
подходит Dict[KeyType, ValueType]
. Если типы могут различаться, используйте Any
.
def func(*args: int, **kwargs: str) -> None:
pass # args принимает целые числа, kwargs – строки
В Python 3.10 и более новых версиях для работы с типами используйте ParamSpec
.
from typing import ParamSpec, Callable
P = ParamSpec('P')
def wrapper(func: Callable[P, int], *args: P.args, **kwargs: P.kwargs) -> int:
return func(*args, **kwargs) # вызывается функция с аргументами и ключевыми словами
Значение протоколов и ABC
Если ваши *args
и **kwargs
соответствуют определённому протоколу или интерфейсу ABC, применяйте Protocol
и ABC в аннотациях типов для обозначения намерений и улучшения читаемости кода.
from typing import Protocol
class SupportsClose(Protocol):
def close(self) -> None:
...
def close_all(*args: SupportsClose) -> None:
for item in args:
item.close() # мы закрываем всё, что поддерживает этот метод
Могущественная перегрузка функций
Декоратор @overload
позволяет объяснить различные комбинации параметров *args
и соответствующих им возвращаемых типов, помогая статическому анализатору понять назначение вашей функции.
from typing import overload, Union
@overload
def process_values(*args: int) -> int: ...
@overload
def process_values(*args: str) -> str: ...
def process_values(*args: Union[int, str]) -> Union[int, str]:
return sum(args) if all(isinstance(arg, int) for arg in args) else ','.join(args)
Строгая типизация *args и **kwargs с помощью TypedDict и Unpack
Используйте TypedDict для более точной типизации **kwargs
, указывая ожидаемые ключи и их типы.
from typing import TypedDict
class Options(TypedDict):
user: str
retries: int
def connect(**kwargs: Options) -> None:
... # осуществляем соединение с сервисом
В Mypy 0.981+ вы можете также использовать Unpack
для распаковки типов:
from typing_extensions import Required, NotRequired, Unpack
class MyParams(TypedDict):
a: Required[int]
b: NotRequired[str]
def my_func(*args: Unpack[MyParams]) -> None:
... # функция принимает распакованные аргументы
Визуализация
Проведём аналогию: упаковка вещей на отпуск работает по принципу *args
и **kwargs
. У нас есть:
- Чемодан (🧳) для *args – складываем разные вещи без организации
- Рюкзак (🎒) для **kwargs – отдельные карманы для конкретных предметов
Типизируем содержимое:
def pack_vacation(*clothes: str, **items: str) -> None:
pass # как следует упаковывать вещи?
Чемодан: [👖, 👕, 👗, 🩳] Рюкзак: {passport: "📄", suncream: "🧴", sunglasses: "🕶️"}
Теперь каждый предмет оснащён ярлычком с типом, что обеспечивает беззаботное путешествие! 🏖️✨
Конвенции и сложности с *args и **kwargs
Работа с *args
*args
может принимать произвольное количество аргументов. Невозможно ограничить число элементов, если они типа int
:
def sum_integers(*args: int) -> int:
return sum(args) # *args "принимает" неограниченное количество чисел
Смешивание типов
Если *args
принимает значения различных типов, используйте object
и реализуйте проверку типов во время выполнения:
def combine(*args: object) -> str:
return " ".join(str(arg) for arg in args if isinstance(arg, (str, int, float)))
# args могут быть разных типов
Сохранение сигнатуры
В Python 3.10 вы можете контролировать типы *args
и **kwargs
, используя ParamSpec
:
from typing import ParamSpec
P = ParamSpec('P')
def repeat_call(func: Callable[P, None], times: int, *args: P.args, **kwargs: P.kwargs) -> None:
for _ in range(times):
func(*args, **kwargs) # вызываем функцию несколько раз
Учет Python 2
В Python 2 аннотации типов не поддерживаются, но можно использовать комментарии для указания типов:
def historical_func(*args, **kwargs):
# type: (*int, **str) -> None
pass # заглянем в прошлое языка Python
Полезные материалы
- PEP 484 – Type Hints — основа аннотаций типов в Python.
- typing — Support for type hints — Python 3.12.2 documentation — официальное руководство по типизации в Python.
- Python Type Checking (Guide) – Real Python — практическое применение проверки типов.
- PEP 3102 – Keyword-Only Arguments — об аргументах, которые передаются только по ключу.
- PEP 3107 – Function Annotations — глубже в мир аннотаций функций Python.
- mypy – Examples — примеры использования проверки типов с помощью mypy.
- Python args and kwargs: Demystified – Real Python — подробно о *args и **kwargs.