Menu
Русский

*args и **kwargs в Python: гибкие позиционные и keyword-аргументы

Что такое *args и **kwargs, когда их использовать и как чисто пробрасывать аргументы между функциями.

Когда не знаешь, сколько аргументов будет

Большинство функций принимает фиксированное число параметров. Но иногда нужна гибкость: логгер, принимающий любое число сообщений; функция-обёртка, пробрасывающая в другую функцию всё, что пришло; функция построения графика, принимающая конфиг, не зная заранее, какие именно опции передаст вызывающий.

Python решает это двумя специальными маркерами в списке параметров: *args и **kwargs.

*args собирает позиционные аргументы

Одна звёздочка говорит «упакуй дополнительные позиционные аргументы в кортеж»:

main.py
Output
Click Run to see the output here.

Внутри функции args — обычный кортеж. По нему можно крутить цикл, индексировать, передавать в len() или брать срезы.

*args обычно стоит рядом с именованными параметрами:

main.py
Output
Click Run to see the output here.

first берёт первый аргумент; *rest упаковывает всё после него в кортеж.

**kwargs собирает keyword-аргументы

Две звёздочки делают то же самое для keyword-аргументов, складывая их в словарь:

main.py
Output
Click Run to see the output here.

Внутри describe kwargs — обычный словарь. Ключи — это имена keyword-аргументов в виде строк.

Используем вместе

Оба можно применять в одной функции. Соглашение — *args перед **kwargs:

main.py
Output
Click Run to see the output here.

Полный порядок параметров слева направо:

  1. Обычные позиционные параметры (обязательные или со значениями по умолчанию).
  2. *args.
  3. Параметры только по ключу (всё после *args нужно передавать по имени).
  4. **kwargs.
main.py
Output
Click Run to see the output here.

title берёт первый позиционный. Остальные позиционные уходят в tags. draft приходится передавать по имени (он после *tags). Любые другие keyword-аргументы попадают в metadata.

Распаковка через * и ** на стороне вызова

Звёздочки работают и в обратную сторону — разворачивают последовательность или словарь в аргументы вызова:

main.py
Output
Click Run to see the output here.

Это невероятно удобно для проброса аргументов:

main.py
Output
Click Run to see the output here.

wrapped не нужно знать, какие аргументы ожидает log. Он просто собирает всё и пробрасывает дальше. Этот паттерн постоянно встречается в декораторах (продвинутая тема) и функциях-обёртках.

Когда *args и **kwargs — плохой выбор

Легко увлечься и засунуть их повсюду. Два предупреждения:

Они прячут, что функция ожидает

Если каждая функция в твоей кодовой базе — это def f(*args, **kwargs), вызывающему коду непонятно, какие аргументы допустимы. Используй именованные параметры, когда можешь, и давай *args/**kwargs нести только по-настоящему переменное число входов или чистый проброс.

Сообщения об ошибках расплываются

Опечатка в имени keyword-аргумента превращается в тихий None или KeyError глубоко внутри функции, вместо моментального «unexpected keyword argument» в точке вызова. Именованные параметры дают заметно лучшую обратную связь.

Правило: по умолчанию предпочитай именованные параметры и тянись к *args/**kwargs только когда функция действительно гибкая или пробрасывает аргументы в другую вызываемую сущность.

Маленький практический пример

Хелпер в духе форматирования вывода, оборачивающий стороннюю функцию и задающий пару значений по умолчанию:

main.py
Output
Click Run to see the output here.

*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-коде. Держись их, если нет конкретной причины выбрать что-то более описательное.

Учитесь программировать с Coddy

НАЧАТЬ