Голая звездочка в аргументах функции?

242

Что делает голая звездочка в аргументах функции?

Когда я посмотрел на модуль рассола , я увидел это:

pickle.dump(obj, file, protocol=None, *, fix_imports=True)

Я знаю об одинарных и двойных звездочках, предшествующих аргументам (для переменного числа аргументов), но это ничего не предшествует. И я уверен, что это не имеет никакого отношения к рассолу. Это, вероятно, просто пример этого происходит. Я узнал его имя только когда отправил это переводчику:

>>> def func(*):
...     pass
...
  File "<stdin>", line 1
SyntaxError: named arguments must follow bare *

Если это имеет значение, я на питоне 3.3.0.

Эрик
источник

Ответы:

221

Голый *используется, чтобы заставить вызывающего использовать именованные аргументы, поэтому вы не можете определить функцию с *аргументом, если у вас нет следующих ключевых аргументов.

Смотрите этот ответ или документацию по Python 3 для более подробной информации.

Kimvais
источник
3
Обратите внимание, что все позиционные (безымянные) аргументы, в том числе *args, должны встречаться раньше, чем голые *.
BallpointBen
4
Также обратите внимание, что есть своего рода аналог, /, который отмечает конец аргументов только для позиционирования ( stackoverflow.com/questions/28243832/… ).
Стивен
2
@BallpointBen: *вместо *args, и наоборот; они не могут сосуществовать в подписи. Вот почему они выбрали *; ранее, *argsбыл единственный способ заставить чисто позиционные аргументы, и он отмечал конец аргументов, которые могли быть переданы позиционно (так как он собирал все оставшиеся позиционные аргументы, они могли достигать следующих именованных аргументов). *означает, что те же «позиционные аргументы не могут выходить за пределы», но отсутствие имени означает «но я их не приму, потому что я решил не предоставлять место для их размещения».
ShadowRanger
70

Хотя оригинальный ответ полностью отвечает на вопрос, просто добавив немного связанной информации. Поведение для единственной звездочки происходит от PEP-3102. Цитирую соответствующий раздел:

The second syntactical change is to allow the argument name to
be omitted for a varargs argument. The meaning of this is to
allow for keyword-only arguments for functions that would not
otherwise take a varargs argument:

    def compare(a, b, *, key=None):
        ...

В простом английском это означает, что для передачи значения ключа вам нужно явно передать его как key="value".

му 無
источник
О, это делает вещи намного яснее. Таким образом, на самом деле наличие аргумента * аналогично аргументу args *, но поскольку вы ничего не назвали, его единственный эффект, вероятно, заключается в том, чтобы спокойно сожрать все оставшиеся позиционные аргументы, чтобы заставить оставшиеся аргументы быть ключевыми словами -только.
Стивен
11
@ Стефен Я тоже изначально думал, что эффект голого *состоит в том, чтобы сожрать оставшиеся позиционные аргументы, но это не так. Передача дополнительных позиционных аргументов, чем ожидает функция, выдает ошибку такого рода:foo() takes exactly 1 positional argument (2 given)
Ajay M
19
def func(*, a, b):
    print(a)
    print(b)

func("gg") # TypeError: func() takes 0 positional arguments but 1 was given
func(a="gg") # TypeError: func() missing 1 required keyword-only argument: 'b'
func(a="aa", b="bb", c="cc") # TypeError: func() got an unexpected keyword argument 'c'
func(a="aa", b="bb", "cc") # SyntaxError: positional argument follows keyword argument
func(a="aa", b="bb") # aa, bb

приведенный выше пример с ** kwargs

def func(*, a, b, **kwargs):
    print(a)
    print(b)
    print(kwargs)

func(a="aa",b="bb", c="cc") # aa, bb, {'c': 'cc'}
laycat
источник
6

Семантически это означает, что аргументы, следующие за ним, предназначены только для ключевых слов, поэтому вы получите ошибку, если попытаетесь указать аргумент без указания его имени. Например:

>>> def f(a, *, b):
...     return a + b
...
>>> f(1, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() takes 1 positional argument but 2 were given
>>> f(1, b=2)
3

Прагматически это означает, что вы должны вызывать функцию с ключевым аргументом. Обычно это делается, когда трудно понять цель аргумента без намека на имя аргумента.

Сравните, например, sorted(nums, reverse=True)с, если вы написали sorted(nums, True). Последнее будет гораздо менее читабельным, поэтому разработчики Python решили заставить вас писать его по-прежнему.

kaya3
источник
4

Предположим, у вас есть функция:

def sum(a,key=5):
    return a + key 

Вы можете вызвать эту функцию двумя способами:

sum(1,2) или sum(1,key=2)

Предположим, вы хотите, чтобы функция sumвызывалась только с использованием ключевых слов.

Вы добавляете *в список параметров функции, чтобы отметить конец позиционных аргументов.

Итак, функция определяется как:

def sum(a,*,key=5):
    return a + key 

можно вызывать только используя sum(1,key=2)

ROK
источник
-1

Я нашел ссылку , чтобы быть очень полезным объяснить *, *argsи **kwargs:

https://pythontips.com/2013/08/04/args-and-kwargs-in-python-explained/

По сути, в дополнение к ответам выше, я узнал с сайта выше (кредит: https://pythontips.com/author/yasoob008/ ) следующее:

С демонстрационной функцией, определенной сначала ниже, есть два примера, один с *argsи один с**kwargs

def test_args_kwargs(arg1, arg2, arg3):
    print "arg1:", arg1
    print "arg2:", arg2
    print "arg3:", arg3

# first with *args
>>> args = ("two", 3,5)
>>> test_args_kwargs(*args)
arg1: two
arg2: 3
arg3: 5

# now with **kwargs:
>>> kwargs = {"arg3": 3, "arg2": "two","arg1":5}
>>> test_args_kwargs(**kwargs)
arg1: 5
arg2: two
arg3: 3

Таким образом, *argsпозволяет динамически создавать список аргументов, которые будут приниматься в порядке их подачи, тогда как **kwargsможет включать передачу аргументов NAMED и может обрабатываться NAME соответственно (независимо от порядка их подачи) ,

Сайт продолжает, отмечая, что правильный порядок аргументов должен быть:

some_func(fargs,*args,**kwargs)
lb_so
источник
2
Этот ответ не имеет ничего общего с вопросом. Он даже использует устаревшую версию Python, которая не имеет этой функции.
Антти Хаапала