Аналогично, * и ** могут использоваться для параметров. Использование * позволяет функции принимать любое количество позиционных аргументов, которые будут собраны в один параметр:
defadd(*values): s = 0 for v in values: s = s + v return s
Теперь, когда функция вызывается как s = add(1, 2, 3, 4, 5), values будет кортеж (1, 2, 3, 4, 5) (который, конечно, выдает результат 15).
При вызове функции одиночная звездочка превращает список в отдельные аргументы (например, zip(*x) совпадает с zip(x1, x2, x3) given x=[x1,x2,x3]), а двойная звездочка превращает словарь в отдельные аргументы ключевого слова (например, f(**k) совпадает с f(x=my_x, y=my_y) given k = {'x':my_x, 'y':my_y}.
В определении функции все наоборот: одиночная звездочка превращает произвольное количество аргументов в список, а двойное начало превращает произвольное количество аргументов ключевого слова в словарь. Например. def foo(*x) означает "foo принимает произвольное количество аргументов, и они будут доступны через x (т.Е. Если пользователь вызовет foo(1,2,3), x будет (1, 2, 3))" и def bar(**k) означает "bar принимает произвольное количество аргументов ключевого слова, и они будут доступны через k ( т.е. если пользователь позвонит bar(x=42, y=23), k будет {'x': 42, 'y': 23})".
Ответ 3
Я нахожу это особенно полезным для хранения аргументов для вызова функции.
Например, предположим, у меня есть несколько модульных тестов для функции 'add':
defadd(a, b): return a + b
tests = { (1,4):5, (0, 0):0, (-1, 3):3 }
for test, result in tests.items(): print('test: adding', test, '==', result, '---', add(*test) == result)
Нет другого способа вызвать add, кроме ручного выполнения чего-то вроде add(test[0], test[1]), что некрасиво. Кроме того, при наличии переменного количества переменных код может получиться довольно уродливым со всеми необходимыми if-операторами.
Еще одно место, где это полезно, - это определение объектов Factory (объектов, которые создают объекты для вас). Предположим, у вас есть некоторый класс Factory , который создает объекты Car и возвращает их. Вы могли бы сделать так, чтобы это myFactory.make_car('red', 'bmw', '335ix') создавало Car('red', 'bmw', '335ix'), а затем возвращало его.
defmake_car(*args): return Car(*args)
Это также полезно, когда вы хотите вызвать конструктор суперкласса.
Ответ 4
Это называется расширенным синтаксисом вызова. Из документации:
Если синтаксическое выражение * появляется в вызове функции, выражение должно вычисляться в последовательности. Элементы из этой последовательности обрабатываются так, как если бы они были дополнительными позиционными аргументами; если есть позиционные аргументы x1, ..., xN, и выражение вычисляет последовательность y1, ..., yM , это эквивалентно вызову с M + N позиционными аргументами x1, ..., xN, y1, ..., yM .
и:
Если синтаксическое выражение ** появляется в вызове функции, expression должно соответствовать отображению, содержимое которого обрабатывается как дополнительные аргументы ключевого слова. В случае, если ключевое слово появляется как в выражении, так и в качестве явного аргумента ключевого слова, возникает исключение TypeError.