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
Одна функция может принимать неограниченное количество позиционных и именованных аргументов. Требуемый порядок в сигнатуре:
- Обычные позиционные параметры
*args- Параметры только для ключевых слов (со значениями по умолчанию)
**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: Trueport и 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):
pass2. Изменение кортежа 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 разрешает имена переменных.