*args — собирает произвольное количество позиционных аргументов в кортеж.
**kwargs — собирает произвольное количество именованных аргументов (ключ=значение) в словарь.
Это позволяет писать функции с гибким интерфейсом:
def my_func(a, b, *args, **kwargs): print(a, b) print(args) print(kwargs) my_func(1, 2, 3, 4, x=10, y=20) # 1 2 # (3, 4) # {'x': 10, 'y': 20}
Тонкости:
Можно ли поменять порядок *args и именованных аргументов со значением по умолчанию, например:
def foo(a, *args, x=10, **kwargs): pass
или обязательно всегда ставить значения по умолчанию после *args?
Ответ:
В Python 3 можно! Вот так (не работало в Python 2):
def foo(a, *args, x=10): pass
Параметры после *args ("keyword-only arguments") могут иметь значения по умолчанию или быть обязательными — их можно задавать только по имени.
История
Передача неправильных аргументов через *args/**kwargs
В сервисах REST API автоматизация маршалинга данных строилась через **kwargs. Лишний параметр не был замечен — функция принимала неожиданное значение в kwargs, что приводило к потере контрольной логики и трудным для отладки багам.
История
Дублирование именованных аргументов
При вызове функции разработчик случайно указал параметр и явно, и через **kwargs, например: my_func(a=1, **{"a": 2}). В результате — TypeError и падение сервиса.
История
Забыли позиционные или именованные только аргументы
При написании декоратора неправильная передача параметров (не соблюден порядок и структура) приводила к тому, что оригинальная функция получала не то количество аргументов, соглашения о которых менялись, и в продакшене начали возникать ошибки вызова TypeError.