Когда не знаешь, сколько аргументов будет
Большинство функций принимает фиксированное число параметров. Но иногда нужна гибкость: логгер, принимающий любое число сообщений; функция-обёртка, пробрасывающая в другую функцию всё, что пришло; функция построения графика, принимающая конфиг, не зная заранее, какие именно опции передаст вызывающий.
Python решает это двумя специальными маркерами в списке параметров: *args и **kwargs.
*args собирает позиционные аргументы
Одна звёздочка говорит «упакуй дополнительные позиционные аргументы в кортеж»:
Внутри функции args — обычный кортеж. По нему можно крутить цикл, индексировать, передавать в len() или брать срезы.
*args обычно стоит рядом с именованными параметрами:
first берёт первый аргумент; *rest упаковывает всё после него в кортеж.
**kwargs собирает keyword-аргументы
Две звёздочки делают то же самое для keyword-аргументов, складывая их в словарь:
Внутри describe kwargs — обычный словарь. Ключи — это имена keyword-аргументов в виде строк.
Используем вместе
Оба можно применять в одной функции. Соглашение — *args перед **kwargs:
Полный порядок параметров слева направо:
- Обычные позиционные параметры (обязательные или со значениями по умолчанию).
*args.- Параметры только по ключу (всё после
*argsнужно передавать по имени). **kwargs.
title берёт первый позиционный. Остальные позиционные уходят в tags. draft приходится передавать по имени (он после *tags). Любые другие keyword-аргументы попадают в metadata.
Распаковка через * и ** на стороне вызова
Звёздочки работают и в обратную сторону — разворачивают последовательность или словарь в аргументы вызова:
Это невероятно удобно для проброса аргументов:
wrapped не нужно знать, какие аргументы ожидает log. Он просто собирает всё и пробрасывает дальше. Этот паттерн постоянно встречается в декораторах (продвинутая тема) и функциях-обёртках.
Когда *args и **kwargs — плохой выбор
Легко увлечься и засунуть их повсюду. Два предупреждения:
Они прячут, что функция ожидает
Если каждая функция в твоей кодовой базе — это def f(*args, **kwargs), вызывающему коду непонятно, какие аргументы допустимы. Используй именованные параметры, когда можешь, и давай *args/**kwargs нести только по-настоящему переменное число входов или чистый проброс.
Сообщения об ошибках расплываются
Опечатка в имени keyword-аргумента превращается в тихий None или KeyError глубоко внутри функции, вместо моментального «unexpected keyword argument» в точке вызова. Именованные параметры дают заметно лучшую обратную связь.
Правило: по умолчанию предпочитай именованные параметры и тянись к *args/**kwargs только когда функция действительно гибкая или пробрасывает аргументы в другую вызываемую сущность.
Маленький практический пример
Хелпер в духе форматирования вывода, оборачивающий стороннюю функцию и задающий пару значений по умолчанию:
*values даёт вызывающему передать любое число элементов; **style проглатывает лишнюю конфигурацию, не требуя делать каждую опцию именованным параметром. Гибко, но не непрозрачно: внутренняя логика точно говорит, какие ключи она читает из style.
Резюме
*argsупаковывает дополнительные позиционные аргументы в кортеж.**kwargsупаковывает дополнительные keyword-аргументы в словарь.- На стороне вызова
*seqи**dictраспаковывают в обратную сторону. - Параметры должны идти в порядке: обычные →
*args→ keyword-only →**kwargs. - Не злоупотребляй — именованные параметры яснее там, где их можно использовать.
Дальше — lambda, способ писать маленькие одноразовые функции прямо в одной строке.
Часто задаваемые вопросы
Что такое *args в Python?
*args собирает все дополнительные позиционные аргументы в кортеж. def f(*args): позволяет вызвать f(1, 2, 3) и получить args равным (1, 2, 3). Имя args — это соглашение; формально можно назвать как угодно, но в сообществе используют *args.
Что такое **kwargs в Python?
**kwargs собирает все дополнительные keyword-аргументы в словарь. def f(**kwargs): позволяет вызвать f(name='Ada', age=30) и получить kwargs как {'name': 'Ada', 'age': 30}. Вместе *args и **kwargs дают функции принимать любую комбинацию аргументов.
Обязательно ли называть их args и kwargs?
Нет, значение имеют звёздочки, а не имена. *values и **options работают точно так же. Но args и kwargs — почти универсальное соглашение в Python-коде. Держись их, если нет конкретной причины выбрать что-то более описательное.