W3docs

Python *args и **kwargs

Узнайте, как *args и **kwargs позволяют функциям Python принимать любое количество позиционных и именованных аргументов — с примерами и типичными шаблонами.

*args и **kwargs — специальный синтаксис Python, позволяющий функции принимать переменное количество аргументов. *args собирает дополнительные позиционные аргументы в кортеж, а **kwargs собирает дополнительные именованные аргументы в словарь. Вместе они дают полную гибкость — можно писать функции, которые работают как с одним аргументом, так и со ста.

На этой странице рассматриваются оба механизма подробно: как они работают, когда их применять, как их комбинировать и каких ошибок следует избегать.

Что такое *args?

Когда перед именем параметра ставится одна звёздочка (*), Python собирает все дополнительные позиционные аргументы, переданные в функцию, в кортеж, связанный с этим именем параметра. Имя args — это соглашение; можно написать *numbers или *values, — но *args понятно всем.

def add_all(*args):
    total = 0
    for n in args:
        total += n
    return total

print(add_all(1, 2, 3))         # 6
print(add_all(10, 20, 30, 40))  # 100
print(add_all())                 # 0

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

Совмещение обычных параметров с *args

Обычные (позиционные) параметры идут первыми; *args перехватывает всё, что следует за ними:

def greet(greeting, *names):
    for name in names:
        print(greeting + ', ' + name + '!')

greet('Hello', 'Alice', 'Bob', 'Charlie')
# Hello, Alice!
# Hello, Bob!
# Hello, Charlie!

greeting заполняется первым аргументом; names получает остальные в виде кортежа. Если вызвать greet('Hi') без дополнительных имён, names будет пустым кортежем и цикл просто не выполнится — без ошибок.

Что такое **kwargs?

Два символа звёздочки (**) перед именем параметра говорят Python собрать все дополнительные именованные аргументы в словарь. Имя kwargs тоже является соглашением; подойдёт любой допустимый идентификатор Python.

def describe(**kwargs):
    for key, value in kwargs.items():
        print(key + ': ' + str(value))

describe(name='Alice', age=30, city='New York')
# name: Alice
# age: 30
# city: New York

Внутри функции kwargs — это обычный словарь. По нему можно итерироваться, обращаться к ключам или передавать его дальше. Вызывающая сторона сама решает, какие ключи передавать — ни один из них не зафиксирован в определении функции.

Когда использовать **kwargs

**kwargs особенно удобен, когда:

  • Функция должна принимать гибкий, открытый набор именованных опций (конфигурация, метаданные, HTML-атрибуты).
  • Вы пишете обёртку, которая должна передавать именованные аргументы в другую функцию, не зная, какие именно они будут.
  • Вы хотите создать словарь из именованных аргументов в читаемом виде (избегая шаблонного кода dict(key=value, ...)).

Совмещение *args и **kwargs

Одна функция может принимать неограниченное количество позиционных и именованных аргументов. Требуемый порядок в сигнатуре:

  1. Обычные позиционные параметры
  2. *args
  3. Параметры только для ключевых слов (со значениями по умолчанию)
  4. **kwargs
def log_event(event, *tags, **metadata):
    print('Event:', event)
    print('Tags:', tags)
    print('Metadata:', metadata)

log_event('login', 'auth', 'user', user_id=42, ip='127.0.0.1')
# Event: login
# Tags: ('auth', 'user')
# Metadata: {'user_id': 42, 'ip': '127.0.0.1'}

event принимает первый позиционный аргумент; tags перехватывает оставшиеся позиционные аргументы; metadata перехватывает все именованные аргументы.

Распаковка аргументов с помощью * и **

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

Распаковка списка или кортежа с помощью *

def multiply(a, b, c):
    return a * b * c

nums = [2, 3, 4]
print(multiply(*nums))  # 24

*nums распаковывает список так, что a=2, b=3, c=4. Это эквивалентно записи multiply(2, 3, 4). Подробнее об операторе распаковки см. в разделе Распаковка кортежей.

Распаковка словаря с помощью **

def power(base, exp):
    return base ** exp

params = {'base': 3, 'exp': 4}
print(power(**params))  # 81

**params сопоставляет каждый ключ словаря с соответствующим именем параметра. Это полезно, когда аргументы хранятся в конфигурационном словаре, формируемом во время выполнения.

Аргументы, передаваемые только по ключу, после *args

Любой параметр, указанный после *args в сигнатуре, может быть передан только по имени (он становится аргументом только для ключевых слов). Это удобный способ добавить необязательные флаги без неоднозначности:

def configure(host, *args, port=80, debug=False):
    print('host:', host)
    print('extra:', args)
    print('port:', port)
    print('debug:', debug)

configure('localhost', 'arg1', port=8080, debug=True)
# host: localhost
# extra: ('arg1',)
# port: 8080
# debug: True

port и debug нельзя задать позиционно, потому что *args уже поглощает все лишние позиционные аргументы. Этот шаблон распространён в библиотечных API — пользователи обязаны явно указывать port=8080, что делает места вызова самодокументируемыми.

Подробное объяснение правил области видимости Python см. в разделе Python Scope.

Передача аргументов в другую функцию

Одно из наиболее практичных применений *args/**kwargs — написание обёрток и декораторов, которые передают аргументы во внутреннюю функцию, не зная, что это за аргументы:

def add_all(*args):
    return sum(args)

def wrapper(*args, **kwargs):
    print('Calling with args:', args, 'kwargs:', kwargs)
    return add_all(*args)

print(wrapper(1, 2, 3))
# Calling with args: (1, 2, 3) kwargs: {}
# 6

Этот шаблон встречается по всей стандартной библиотеке Python и лежит в основе декораторов и функций высшего порядка.

Полный порядок сигнатуры

Python требует строгого порядка всех видов параметров. Полный порядок таков:

ПозицияВидПример
1Только позиционные (Python 3.8+)a, b, /
2Обычные позиционные или именованныеx, y
3Переменное число позиционных*args
4Только именованныеflag=True
5Переменное число именованных**kwargs

Нарушение этого порядка вызывает SyntaxError. Функция, использующая все пять видов, выглядит так:

def full_sig(pos1, pos2, /, normal, *args, kw_only, **kwargs):
    print(pos1, pos2, normal, args, kw_only, kwargs)

full_sig(1, 2, 3, 4, 5, kw_only='k', extra='e')
# 1 2 3 (4, 5) k {'extra': 'e'}

В повседневном коде редко нужны все пять видов сразу. Наиболее распространённые шаблоны: только *args, только **kwargs или *args с последующим **kwargs.

Аннотации типов

К *args и **kwargs можно добавлять подсказки типов. Аннотация применяется к каждому отдельному элементу, а не к кортежу или словарю в целом:

from typing import Any

def add_all(*args: float) -> float:
    return sum(args)

def describe(**kwargs: Any) -> None:
    for key, value in kwargs.items():
        print(f'{key}: {value}')

print(add_all(1.5, 2.5, 3.0))  # 7.0
describe(name='Bob', score=99)
# name: Bob
# score: 99

*args: float означает, что каждый элемент args ожидается типа float. **kwargs: Any означает, что значения могут быть любыми. Это удовлетворяет инструменты статического анализа, сохраняя гибкость во время выполнения.

Типичные ошибки

1. Неправильный порядок аргументов в сигнатуре

Размещение **kwargs перед *args вызывает SyntaxError:

# Wrong — raises SyntaxError
# def bad(name, **kwargs, *args): ...

# Correct
def good(name, *args, **kwargs):
    pass

2. Изменение кортежа args

args — это кортеж и потому неизменяем. Если нужно изменить аргументы, сначала преобразуйте их в список:

def double_all(*args):
    items = list(args)      # mutable copy
    items = [x * 2 for x in items]
    return items

print(double_all(1, 2, 3))  # [2, 4, 6]

3. Затенение имени обязательного параметра

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

4. Злоупотребление **kwargs вместо явных параметров

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

Итог

ВозможностьСинтаксисЧто собираетТип внутри функции
Переменное число позиционных аргументов*argsДополнительные позиционные аргументыtuple
Переменное число именованных аргументов**kwargsДополнительные именованные аргументыdict
Распаковка последовательности при вызовеfunc(*seq)Список/кортеж → позиционные аргументы
Распаковка словаря при вызовеfunc(**mapping)Словарь → именованные аргументы

По смежным темам см.: Функции Python — основы функций; Python Lambda — анонимные функции; Python Scope — как Python разрешает имена переменных.

Practice

Практика
In Python, what does *args do when used in a function definition?
In Python, what does *args do when used in a function definition?
Was this page helpful?