
Да будет холивар! Использовать args/kwargs или не использовать, это показатель профессионализма или базовые знания, без которых должно быть стыдно? Часто листая github различных проектов натыкаешься на наличие данных аргументов в функциях просто потому что. И данная статья натолкнула на пообщаться на эту тему. Вообще, стараюсь не использовать неконтролируемое аргументирование на практике, но на сколько это вообще распространенный метод программирования? Делитесь в комментариях. И приятного чтения.
В Интернете полно обучалок, которые научат вас использовать *args и **kwargs при определении функции в Python. Возможно, вы уже часами пытаетесь понять, как раскрыть их потенциал. Может быть, после всего этого исследования вы теперь чувствуете в них уверенность.
Не надо!
Мощные инструменты опасны. Вы могли облегчить свою жизнь, но запомните мои слова, они вскоре вернутся, чтобы преследовать вас.
Но почему?
Немного основ
Параметры в Python функции могут принимать два типа аргументов:
-
Позиционные аргументы, которые передаются позиционно.
-
Именованные аргументы, которые передаются с ключевыми словами.
def foo(start, end): print(start, end)
Например, foo ('Hi', end = 'Bye!') Передает позиционный аргумент "Hi" и именованный аргумент "Bye!", где ключевым словом выступает end для функции foo. Параметры функции предопределены; количество параметров, принимаемых в функции, фиксировано. Однако это не всегда так.
*args позволяет передавать вашей функции произвольное количество позиционных аргументов. Звездочка * — параметр распаковки. Параметры упаковываются в виде итерируемого кортежа внутри функции.
def foo(*args): print(type(args)) for arg in args: print(arg) foo(1, 2, 'end') # <class 'tuple'> # 1 # 2 # end
С другой стороны, **kwargs позволяет передавать вашей функции произвольное количество аргументов с ключевыми словами. Поскольку у каждого именованного аргумента есть ключевое слово и значение, он сгруппирован как итерируемый словарь внутри функции.
def foo2(**kwargs): print(type(kwargs)) for keyword, value in kwargs.items(): print(f'{keyword}={value}') foo2(a=1, b=2, z='end') # <class 'dict'> # a=1 # b=2 # z=end

Проблема
В большинстве случаев вам действительно не нужны *args и **kwargs. Как часто вы не знаете, сколько аргументов должна получить предопределенная ВАМИ функция?
Код гораздо сложнее отлаживать, если вы злоупотребляете в нем подобными решениями, потому что вы позволяете передавать произвольное количество аргументов функции, и функция может вести себя непредсказуемо.
Явное лучше, чем неявное. — Дзен Python
Когда всё-таки использовать аргументы?
Если кратко: используйте их, когда они вам действительно нужны. Например, функция с множеством необязательных полей, и некоторые из них используются только в редких ситуациях. Скажем, функция строит график, и вы можете передавать различные необязательные аргументы, чтобы изменить его цвет, стиль, размер и т.д.
Каждый раз, когда вы используете *args и/или **kwargs, убедитесь, что вы пишите к функциям ясную документацию, чтобы избежать путаницы.
Есть один сценарий, в котором их использование может быть неизбежным. Если вы создаете оболочку для функции с неизвестными аргументами, вам нужно будет принять произвольное количество позиционных и именованных аргументов, а затем передать их функции.
Например, декораторы в Python работают как оболочки, которые изменяют поведение кода, не изменяя сам код функции, тем самым расширяя дополнительные функции.

В следующем примере мы создаем трассировку, которая выводит имя выполняемой функции в качестве проверки работоспособности. Декоратор применяется к функции с помощью @trace поверх функции, как показано ниже. Поскольку мы хотим применить этот декоратор к любым функциям с любым количеством аргументов, нам нужно использовать *args и **kwargs.
def trace(func): def print_in(*args, **kwargs): print('Executing function', func.__name__) return func(*args, **kwargs) return print_in @trace def calc(a,b): print(f'a+b is {a+b}, a-b is {a-b}.') calc(1,2) # Executing function calc # a+b is 3, a-b is -1. @trace def add_all(*args): print(reduce(lambda a,b:a+b, args)) a = add_all(1,2,3,4,5) # Executing function add_all # 15
Выводы
По возможности избегайте их.
Обратите внимание, что args и kwargs так называются просто по соглашению. Вы можете называть их как хотите. Именно звездочки * и ** дают функциям ту самую мощь.
ссылка на оригинал статьи https://habr.com/ru/post/534672/
Добавить комментарий