Как использовать *args и **kwargs в Python
args и kwargs позволяют принимать переменное число позиционных и именованных аргументов в функциях Python. Используйте args для набора позиционных значений, kwargs для именованных пар ключ:значение. Чётко документируйте интерфейс функции и предпочитайте явные параметры там, где важна читаемость и безопасность.
Краткое введение
В Python функции могут принимать три основных типа аргументов: стандартные (фиксированные), переменные позиционные (args) и переменные именованные (kwargs). Стандартные аргументы просты, но ограничены числом и порядком. args и kwargs делают интерфейс функции гибким — она может принять произвольное число входных значений.
Выбор способа передачи аргументов зависит от назначения функции и предпочтений по стилю кода.
Базовый пример функции
Простейшая функция объявляет фиксированное число анонимных аргументов:
def addnum(a, b, c):
return a + b + cОна работает, но принимает ровно три аргумента. Передача меньшего или большего числа вызовет TypeError. Решать проблему созданием множества перегруженных функций неудобно — лучше использовать переменные аргументы.
Что такое *args
*args собирает дополнительные позиционные аргументы в кортеж. Имя args — произвольное; важен символ звездочки. Это удобно, когда вы хотите принимать произвольное число элементов, например, сумма чисел в калькуляторе.
Пример использования *args
def addnum(*args):
total = 0
for num in args:
total = total + num
return total
print(addnum(10, 1, 12, 12, 4, 54, 5))
print(addnum(14, 54, 5))
print(addnum(10, 5))Практическая подсказка: если аргументы уже в списке или кортеже, распакуйте их с помощью оператора *:
ums = [1, 2, 3, 4]
print(addnum(*nums))Аннотации типов для *args
Можно добавлять типы в аннотациях:
def addnum(*args: int) -> int:
return sum(args)Такая аннотация подсказывает, что ожидаются целые числа; инструменты статической проверки кода увидят подсказку.
Что такое kwargs
kwargs собирает именованные (ключ=значение) аргументы в словарь. Это удобно, когда параметры по смыслу имеют имена или когда список опций меняется во времени.
Пример использования kwargs
def weekly_attendance(weekdays): total_attendees = 0 for attendees in weekdays.values(): total_attendees = total_attendees + attendees return total_attendees print(weekly_attendance(monday = 265, tuesday = 698, wednesday = 365, thursday = 463, friday = 234)) print(weekly_attendance(monday = 265, friday = 234)) print(weekly_attendance(wednesday = 365, thursday = 463, friday = 234))
Подсказка: если параметры уже в словаре, распакуйте его с помощью :
data = {'monday': 265, 'friday': 234} print(weekly_attendance(data))
Порядок и сочетание аргументов
Когда вы смешиваете разные виды параметров, порядок в объявлении важен:
- Сначала позиционные и именованные с дефолтом
- Потом *args
- Затем аргументы, обязательные только по имени (keyword-only), если нужно
- И в конце **kwargs
Пример гибкой сигнатуры:
def demo(a, b=2, *args, c=10, **kwargs):
print('a=', a)
print('b=', b)
print('args=', args)
print('c=', c)
print('kwargs=', kwargs)
# Вызовы
Demo_args = (7, 8, 9)
demo(1, *Demo_args, c=99, extra='x')Заметьте: аргумент c после *args становится обязательным именованным, если вы не зададите ему значение по умолчанию.
Распространённые паттерны и альтернативы
- Явные параметры плюс kwargs: когда важно понятное API, определите ключевые параметры явно, а дополнительную гибкость отдайте kwargs.
- Использовать коллекции: если ожидается множество однотипных значений, может быть лучше принимать список или кортеж вместо *args — это упрощает тестирование и типизацию.
- dataclasses и Pydantic: для сложных конфигураций предпочтительны явные модели данных.
Когда не стоит использовать args и *kwargs
Important: избегайте широкого применения args/*kwargs в публичных API и библиотеках, где важна стабильность интерфейса и автодокументация. Минусы:
- Снижается читаемость интерфейса
- Труднее проверить входные параметры и их типы
- Автодокументирование и подсказки в IDE хуже
Предпочитайте явные параметры для важных функций.
Частые ошибки и как их избежать
- Ошибка порядка аргументов при объявлении функции — внимательно следите за позицией *args
- Перезапись ключей при объединении словарей — при распаковке нескольких словарей ключи справа переопределяют левые
- Ожидание конкретных типов без валидации — добавьте проверки или аннотации и используйте инструменты статической проверки
Тесты и критерии приёмки
Небольшой набор тестовых случаев для функций с args/*kwargs (pytests-подобная форма):
def test_addnum_basic():
assert addnum(1, 2, 3) == 6
def test_addnum_empty():
assert addnum() == 0
def test_weekly_attendance_subset():
assert weekly_attendance(monday=100, friday=50) == 150
def test_demo_mixed():
demo(1, 2, 3, c=4, x=5) # просто проверить, что не бросает исключениеКритерии приёмки: функции должны корректно обрабатывать пустые и различные комбинации аргументов, не порождать TypeError при ожидаемых вариантах вызова и давать понятные сообщения об ошибках в некорректных ситуациях.
Роль‑ориентированные чеклисты
Для разработчика:
- Определить, нужны ли args/*kwargs
- Добавить аннотации типов
- Написать тесты на крайние случаи
Для ревьювера:
- Проверить, что публичный API остаётся читаемым
- Убедиться, что нет потери безопасности при использовании **kwargs
- Проверить документацию и примеры
Для документатора:
- Привести примеры вызовов и распаковки
- Ясно указать ожидаемые типы и ограничения
Мини‑методология проектирования сигнатуры функции
- Определить минимальный набор обязательных аргументов
- Выделить аргументы с дефолтным значением
- Решить, нужны ли позиционные «хвосты» (*args)
- Решить, нужны ли дополнительные именованные опции (**kwargs)
- Документировать и покрыть тестами
Ментальные модели
- *args — это «список без ключей», коллекция позиционных элементов
- **kwargs — это «словарь опций», набор именованных настроек
- Явные параметры — контракт функции; args/*kwargs — расширение этого контракта
Примеры расширенного использования
Обработка и фильтрация kwargs по набору допустимых ключей:
ALLOWED = {'timeout', 'retries'} def configure(kwargs): config = {k: v for k, v in kwargs.items() if k in ALLOWED} return config print(configure(timeout=10, retries=3, debug=True)) # debug будет отброшен
Комбинация распаковки и передачи дальше:
def wrapper(*args, **kwargs):
# добавить значение по умолчанию для ключа, если не передан
kwargs.setdefault('safe', True)
return inner(*args, kwargs)Риски и рекомендации по безопасности
- Не доверяйте без проверки ключам и значениям из kwargs, особенно если данные приходят извне
- При динамической передаче аргументов через **kwargs избегайте исполнения кода на основе имен ключей
Краткая сводка фактов
- *args собирает позиционные аргументы в кортеж
- **kwargs собирает именованные аргументы в словарь
- Их можно распаковывать обратно с помощью и *
- Для публичных API предпочитайте явные параметры
1‑линейный глоссарий
- *args — кортеж дополнительный позиционных аргументов
- **kwargs — словарь дополнительных именованных аргументов
- распаковка — использование и * для передачи коллекций как аргументов
Итог
args и kwargs — мощные инструменты для повышения гибкости функций. Используйте их там, где это оправдано: для вспомогательных функций, внутренних утилит и случаев с динамическими наборами опций. В публичных и критичных по читаемости местах отдавайте предпочтение явным параметрам, дополняя их хорошо задокументированными args/kwargs при необходимости.
Summary
- Используйте *args для произвольного числа позиционных аргументов
- Используйте **kwargs для произвольного числа именованных опций
- Документируйте поведение и пишите тесты
- Избегайте чрезмерной гибкости в публичных API
Похожие материалы
Как вручную извлечь APK и установить на Android
Пипетка и заливка в Procreate — быстрое руководство
DIY Stream Deck на Raspberry Pi Pico
Как защитить разделы OneNote паролем
Сессии в React: cookies и sessionStorage