Раскрытие списка аргументов *args и **kwargs

borntohack

змееуст
Команда форума
Модератор
Апр 22, 2020
78
62
18
39
Москва, РФ
Во многих примерах по python часто встречаются вызовы функций с аргументами *args,**kwargs. Но не всегда понятно, что это и как с этим работать.

Для начала, хочу сказать, что важными в этом контексте являются только "звездочки" (их правильно называют "asterisk"). Само же наименование может быть любым. *args и **kwargs просто общеприняты для указания в примерах.

Обычно, мы описываем функции известными аргументами:
Python:
def square_if_even(x, y):
    if not y%2:
        return x**2
    else:
        return x

Но иногда нам нужно описать функцию с произвольным количеством аргументов. Например, мы хотим посчитать общий вес всех товаров в покупательской корзине.
Зачастую, мы делаем один аргумент - список всех весов, и затем итерируемся по нему:
Python:
def total_weight(weightlist):
    return sum(weightlist)
print(total_weight([1,2,3,4,5,6,7,8,9])
но, что произойдет, если мы передадим в функцию не список, а просто веса (забудем про [])?
Интерпретатор вернет исключение о недопустимом количестве аргументов, поскольку ожидается один и список, а мы передали 9 чисел.
Эту задачу можно решить, используя итеративное раскрытие произвольного списка аргументов.
Взгляните на решение:
Python:
def total_weight(*weights):
    return sum(weights)
print(total_weight(1,2,3,4,5,6,7,8,9))
В данном случае оператор раскрытия списка аргументов приводит все переданные в него аргументы в итерируемый формат. Теперь мы можем передавать в функцию сколько угодно аргументов, функция нам их проссумирует. Единственное, что нужно учесть - для функции sum описанной внутри функции - все аргументы должны поддерживать суммирование заданных типов. Иначе получите ошибку суммирования. В любом случае, раскрытие аргументов произойдет ожидаемым способом.

Иногда, мы хотим написать функцию с именованными аргументами (keyword arguments). Это когда аргументы в функцию передаются по имени (name=Vasya) например.
В простых случаях мы пишем что то такое:
Python:
def some_func(name,surname):
    return "Имя: "+name+", Фамилия: "+surname
print(some_func("Иван","Петров"))
Для произвольного списка таких аргументов служит оператор ** (двойной астериск):
Python:
def some_func(**kwargs):
    return "Имя: "+kwargs["name"]+"Фамилия: "+kwargs["surname"]
print(some_func(name="Иван",surname="Петров"))
В целом, работа с произвольным списком именованных аргументов похожа на работу с произвольным списком обычных аргументов. Различие лишь в том, что доступ к ним осуществляется по ключу.

В определении любых функций можно комбинировать аргументы. PEP8 определяет это так:
Python:
def funcname(arg,*args,**kwargs)
Т.е. сначала ожидаемые аргументы, затем произвольный список неименованных аргументов, затем произвольный список именованных аргументов.

Напоследок, есть интересное применение "астерискам" в случаях, формально не связанных с функциями.
В статье "Маппинг списков" есть вариант приведения результата маппинга к типу list:
Код:
nwlist = list(map(str,lst))
Однако, тот же результат можно достичь с помощью "астериска", если правильно понять, как он работает.
Поскольку для создания объекта типа list необходимо перечислить его элементы через запятую:
Python:
nwlist=[1,2,3,4,5]
Ничего не мешает нам обработать в этом конструкторе результат маппинга, как список неименованных аргументов:
Python:
nwlist = [*map(str,lst)]
Это полностью эквивалентная запись.

Пользуйтесь с умом!
 
Последнее редактирование:

Форум IT Специалистов