Что означают *args и **kwargs в аргументах функций Python
Что проверяют
Понимаете ли вы механику передачи аргументов, а не только помните, что звёздочка означает «сколько угодно». Следом обычно просят написать декоратор, который пробрасывает аргументы дальше, или спрашивают про порядок параметров и keyword-only аргументы.
Как отвечать
Имена условны, работает звёздочка:
- *`args
**: собирает лишние позиционные аргументы в кортежtuple`; - `kwargs
**: собирает лишние именованные аргументы в словарьdict` со строковыми ключами; - распаковка при вызове:
f(*items)раскладывает любую итерируемую последовательность в позиционные аргументы,f(**options)раскладывает словарь в именованные. Это обратная операция, и её часто путают с объявлением.
Порядок в сигнатуре фиксирован: def f(a, /, b, *args, c, d=2, **kwargs). Всё до / передаётся только позиционно (синтаксис с Python 3.8), всё после *args только по имени. Одиночная звёздочка без имени, def f(*, timeout), заставляет вызывающего писать timeout=5 явно, и для флагов это хорошая практика.
Главный практический сценарий это прокидывание аргументов: декоратор с def wrapper(*args, **kwargs): return func(*args, **kwargs) и functools.wraps, вызов super().__init__(*args, **kwargs) при наследовании, обёртки над чужим API. В аннотациях *args: int означает, что каждый элемент int. Для точной типизации обёрток есть ParamSpec с P.args и P.kwargs (Python 3.10), а для kwargs с разными типами Unpack[TypedDict] по PEP 692 (Python 3.12).
Распаковка работает и вне вызовов: {**defaults, **overrides} сливает словари, правый выигрывает, а first, *rest = items собирает хвост в список.
Где спотыкаются
Думают, что args это список. Это кортеж, поэтому args.append() падает с AttributeError.
Используют **kwargs, чтобы не проектировать сигнатуру. Такая функция молча проглатывает опечатку в имени параметра, а IDE и mypy перестают подсказывать. Явные параметры лучше, kwargs уместны там, где вы действительно передаёте их дальше.
Путают порядок: пишут def f(**kwargs, *args) и получают SyntaxError, или не могут объяснить, почему параметр после *args без значения по умолчанию становится обязательным именованным.