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

Представьте себе такой кейс: есть две библиотеки, одна из которых имеет полностью прописанный интерфейс у функции foo. Вторая определяет функцию boo, которая вызывает foo. Интерфейс boo «свёрнут» с помощью *args и **kwargs:

def foo(arg1=None, arg2=None):
    pass


def boo(*args, **kwargs):
    foo(*args, **kwargs)

В коде проекта есть функция do_magic, которая использует boo:

def do_magic(*args, **kwargs):
    boo(*args, **kwargs)

Задача такая: если arg1 в do_magic прилетает со значением по умолчанию, то дальше его нужно отправить со значением True.

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

def do_magic(*args, **kwargs):
    if 'arg1' not in kwargs and len(args) == 0:
        kwargs['arg1'] = True
    boo(*args, **kwargs)

Работу мы выполнили: учли, что arg1 может быть передан как именованный параметр, так и как неименованный. Функция работает как надо. Но есть путь проще, элегантнее и с меньшим количеством кода:

def do_magic(arg1=True, *args, **kwargs):
    boo(arg1=arg1, *args, **kwargs)

Почему второй вариант лучше?

  1. Простота и читаемость. Код становится короче и понятнее: сразу видно, какой параметр модифицируется и какое у него значение по умолчанию.
  2. Меньше проверок. Не нужно вручную проверять наличие параметра в args/kwargs — Python сам обработает передачу аргументов.
  3. Надёжность. Снижается риск ошибок из‑за сложной логики проверки позиций в args или дублирования ключей в kwargs.
  4. Соответствие идиомам Python. Явное указание параметров делает интерфейс функции понятнее для других разработчиков и инструментов статического анализа.
  5. Удобство поддержки. Если потребуется изменить логику обработки других аргументов, код будет легче модифицировать.

Важные нюансы при использовании второго подхода:

  • Если arg1 уже передан как позиционный аргумент (в args), явное указание arg1=arg1 приведёт к ошибке «multiple values for argument». Чтобы избежать этого, убедитесь, что логика вызова не допускает дублирования.
  • При наличии большого числа параметров такой подход может усложнить сигнатуру функции. В таких случаях стоит рассмотреть использование **kwargs с предварительной обработкой или рефакторинг интерфейса.
  • Для сложных сценариев модификации аргументов можно комбинировать оба подхода: «развернуть» ключевые параметры, а остальные передать через *args/**kwargs.