Зачем использовать упакованные * args/ * * kwargs вместо передачи списка / dict?
Если я не знаю, сколько аргументов будет передано функции, я мог бы написать функцию, используя упаковку аргументов:
def add(factor, *nums):
"""Add numbers and multiply by factor."""
return sum(nums) * factor
В качестве альтернативы я мог бы избежать упаковки аргументов, передав список чисел в качестве аргумента:
def add(factor, nums):
"""Add numbers and multiply by factor.
:type factor: int
:type nums: list of int
"""
return sum(nums) * factor
Есть ли преимущество в использовании упаковки аргументов *args
перед передачей списка чисел? Или есть ситуации, когда один из них более уместен?
2 ответа:
*args
/**kwargs
имеет свои преимущества, как правило, в тех случаях, когда вы хотите иметь возможность передавать в распакованной структуре данных, сохраняя при этом возможность работать с упакованными. Хорошим примером является Python 3print()
.print('hi') print('you have', num, 'potatoes') print(*mylist)
Сравните это с тем, что было бы, если бы
print()
только взял упакованную структуру, а затем расширил ее в функции:print(('hi',)) print(('you have', num, 'potatoes')) print(mylist)
В этом случае,
*args
/**kwargs
это очень удобно.Конечно, если вы ожидаете, что функция всегда будет передаваться несколько аргументов, содержащихся в структуре данных, как это делают
sum()
иstr.join()
, было бы более разумно исключить синтаксис*
.
Речь идет об API: * args предоставляет лучший интерфейс, поскольку он утверждает, что метод принимает произвольное число аргументов, и это все - никаких дальнейших предположений. Вы точно знаете, что сам метод не будет делать ничего другого со структурой данных, содержащей различные аргументы, и что никакая специальная структура данных не требуется.
Теоретически можно также принять словарь со значениями, равными None. А почему бы и нет? Это накладно и не нужно. Для меня, принимая список, когда вы можете принять, что вараргс добавляет накладные расходы. (как было указано в одном из комментариев)
Кроме того, varargs-это хороший способ гарантировать согласованность и хороший контракт между вызывающей и вызываемой функциями. Никаких предположений быть не может.Когда и если вам нужен список, то вы знаете, что вам нужен список!
Ах, обратите внимание, что f (*args) не то же самое, что f(list): второй хочет список, первый принимает произвольное число параметров (0 включено). Ладно, давайте определите второй аргумент как необязательный:
def f(l = []): pass
Круто, теперь у вас есть две проблемы, потому что вы должны убедиться, что вы не изменяете аргумент l: значения параметров по умолчанию. По какой причине? Потому что тебе не нравятся Арги. :)
PS: Я думаю, что это один из самых больших недостатков динамических языков: вы больше не видите интерфейс, но да! есть интерфейс!