Naga gwiazdka w argumentach funkcji?


242

Do czego służy pusta gwiazdka w argumentach funkcji?

Kiedy spojrzałem na moduł marynaty , widzę to:

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

Wiem o pojedynczych i podwójnych gwiazdkach poprzedzających argumenty (dla zmiennej liczby argumentów), ale to nic nie poprzedza. I jestem prawie pewien, że to nie ma nic wspólnego z marynatą. To prawdopodobnie tylko przykład tego, co się dzieje. Nauczyłem się jego nazwy dopiero, gdy wysłałem to do tłumacza:

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

Jeśli to ma znaczenie, korzystam z Pythona 3.3.0.


Odpowiedzi:


221

Gołe *jest używane, aby zmusić program wywołujący do używania nazwanych argumentów - więc nie można zdefiniować funkcji *jako argumentu, gdy nie ma następujących argumentów słowa kluczowego.

Aby uzyskać więcej informacji, zobacz tę odpowiedź lub dokumentację Python 3 .


3
Zauważ, że wszystkie argumenty pozycyjne (nienazwane), w tym *args, muszą występować przed samą wersją *.
BallpointBen

4
Zauważ też, że istnieje swego rodzaju odpowiednik /, który oznacza koniec argumentów tylko pozycyjnych ( stackoverflow.com/questions/28243832/… ).
Stephen

2
@BallpointBen: *jest na miejscu *argsi odwrotnie; nie mogą współistnieć w sygnaturze. Właśnie dlatego wybrali *; poprzednio *argsbył jedynym sposobem na wymuszenie argumentów czysto pozycyjnych i oznaczał koniec argumentów, które można przekazywać pozycyjnie (ponieważ zebrał wszystkie pozostałe argumenty pozycyjne, mogły dotrzeć do następujących nazwanych argumentów). *oznacza te same „argumenty pozycyjne nie mogą wykraczać poza to”, ale brak nazwy oznacza „ale ja ich w ogóle nie zaakceptuję, ponieważ nie zdecydowałem się na miejsce, w którym można je umieścić”.
ShadowRanger

70

Podczas gdy oryginalna odpowiedź całkowicie odpowiada na pytanie, wystarczy dodać trochę powiązanych informacji. Zachowanie pojedynczej gwiazdki pochodzi od PEP-3102. Cytując pokrewną sekcję:

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):
        ...

W prostym języku angielskim oznacza to, że aby przekazać wartość klucza, musisz jawnie przekazać ją jako key="value".


Och, to sprawia, że ​​wszystko jest znacznie wyraźniejsze. Zatem posiadanie argumentu * jest jak argumentowanie argumentów *, ale skoro nic go nie nazwałeś, jego jedynym efektem jest prawdopodobnie ciche pochłonięcie wszystkich pozostałych argumentów pozycyjnych, aby zmusić pozostałe argumenty do słowa kluczowego -tylko.
Stephen

11
@Stephen Ja też pierwotnie myślałem, że efekt bosego to pożeranie *pozostałych argumentów pozycyjnych, ale tak nie jest. Przekazanie dodatkowych argumentów pozycyjnych, niż oczekuje funkcja, daje tego rodzaju błąd: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

powyższy przykład z ** kwargs

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

func(a="aa",b="bb", c="cc") # aa, bb, {'c': 'cc'}

6

Semantycznie oznacza to, że następujące po nim argumenty są tylko słowami kluczowymi, więc pojawi się błąd, jeśli spróbujesz podać argument bez podania jego nazwy. Na przykład:

>>> 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

Pragmatycznie oznacza to, że musisz wywołać funkcję z argumentem słowa kluczowego. Zwykle robi się to, gdy trudno jest zrozumieć cel argumentu bez wskazówki podanej w nazwie argumentu.

Porównaj np. sorted(nums, reverse=True)Vs. jeśli napisałeś sorted(nums, True). Ten ostatni byłby o wiele mniej czytelny, więc programiści Pythona postanowili zmusić cię do napisania go w ten sam sposób.


4

Załóżmy, że masz funkcję:

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

Możesz wywołać tę funkcję na 2 sposoby:

sum(1,2) lub sum(1,key=2)

Załóżmy, że chcesz, aby funkcja sumbyła wywoływana tylko za pomocą argumentów słów kluczowych.

Dodajesz *do listy parametrów funkcji, aby zaznaczyć koniec argumentów pozycyjnych.

Funkcja zdefiniowana jako:

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

można wywołać tylko za pomocą sum(1,key=2)


-1

Znalazłem na poniższy link, aby być bardzo pomocny wyjaśniając *, *argsi **kwargs:

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

Zasadniczo, oprócz powyższych odpowiedzi, dowiedziałem się z powyższej strony (kredyt: https://pythontips.com/author/yasoob008/ ), co następuje:

Po zdefiniowaniu funkcji demonstracyjnej jako pierwszej poniżej, istnieją dwa przykłady, jeden z *argsi jeden z**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

Więc *argspozwala dynamicznie zbudować listę argumentów, które zostaną podjęte w kolejności, w jakiej są one karmione, natomiast **kwargsmożna włączyć przechodząc nazwanych argumentów, i mogą być przetwarzane przez NAME odpowiednio (niezależnie od kolejności, w jakiej są one karmione) .

Strona kontynuuje, zauważając, że poprawna kolejność argumentów powinna być:

some_func(fargs,*args,**kwargs)

2
Ta odpowiedź nie ma prawie nic wspólnego z pytaniem. Korzysta nawet z przestarzałej wersji Pythona, która nie ma tej funkcji.
Antti Haapala
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.