Nacktes Sternchen in Funktionsargumenten?

240

Was bewirkt ein bloßes Sternchen in den Argumenten einer Funktion?

Wenn ich mir das Gurkenmodul anschaue , sehe ich Folgendes:

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

Ich kenne ein einzelnes und ein doppeltes Sternchen vor Argumenten (für eine variable Anzahl von Argumenten), aber dies geht nichts voraus. Und ich bin mir ziemlich sicher, dass dies nichts mit Gurke zu tun hat. Das ist wahrscheinlich nur ein Beispiel dafür. Ich habe den Namen erst erfahren, als ich ihn an den Dolmetscher geschickt habe:

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

Wenn es darauf ankommt, bin ich auf Python 3.3.0.

Eric
quelle

Antworten:

220

Bare *wird verwendet, um den Aufrufer zu zwingen, benannte Argumente zu verwenden. Sie können also keine Funktion mit *als Argument definieren, wenn Sie keine folgenden Schlüsselwortargumente haben.

Weitere Informationen finden Sie in dieser Antwort oder in der Python 3-Dokumentation .

Kimvais
quelle
3
Beachten Sie, dass alle positionellen (unbenannten) Argumente, einschließlich *args, vor dem Bare stehen müssen *.
BallpointBen
4
Beachten Sie auch, dass es eine Art Gegenstück gibt, / das das Ende von Nur-Positions-Argumenten markiert ( stackoverflow.com/questions/28243832/… ).
Stephen
2
@BallpointBen: *ist anstelle von *argsund umgekehrt; Sie können in einer Signatur nicht koexistieren. Deshalb haben sie gewählt *; Zuvor *argswar die einzige Möglichkeit , rein Positionsargumente zu zwingen, und es markiert das Ende der Argumente , die konnte positionsübergeben werden (da sie alle verbleibenden Positions Argumente gesammelt, sie könnten die folgenden benannten Argumente erreichen). *bedeutet, dass die gleichen "Positionsargumente hier nicht darüber hinausgehen können", aber das Fehlen eines Namens bedeutet "aber ich werde sie überhaupt nicht akzeptieren, weil ich mich dafür entschieden habe, keinen Platz für sie zu schaffen".
ShadowRanger
70

Während die ursprüngliche Antwort die Frage vollständig beantwortet, fügen Sie einfach ein paar verwandte Informationen hinzu. Das Verhalten für das einzelne Sternchen ergibt sich aus PEP-3102. Zitieren des verwandten Abschnitts:

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

In einfachem Englisch bedeutet dies, dass Sie den Wert für key explizit als übergeben müssen, um ihn zu übergeben key="value".

mu 無
quelle
Oh, das macht die Dinge viel klarer. Ein Argument * zu haben ist also wie ein Argument args * zu haben, aber da Sie es nicht benannt haben, besteht seine einzige Wirkung wahrscheinlich darin, alle verbleibenden Positionsargumente leise zu verschlingen, um die verbleibenden Argumente als Schlüsselwort zu erzwingen -nur.
Stephen
11
@Stephen Ich dachte auch ursprünglich, der Effekt von Bare *ist, verbleibende Positionsargumente zu verschlingen, aber das ist nicht der Fall. Das Übergeben zusätzlicher Positionsargumente als von der Funktion erwartet, führt zu einem Fehler dieser Art:foo() takes exactly 1 positional argument (2 given)
Ajay M
18
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

das obige Beispiel mit ** kwargs

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

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

Semantisch bedeutet dies, dass die darauf folgenden Argumente nur Schlüsselwörter sind. Sie erhalten also eine Fehlermeldung, wenn Sie versuchen, ein Argument anzugeben, ohne dessen Namen anzugeben. Beispielsweise:

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

Pragmatisch bedeutet dies, dass Sie die Funktion mit einem Schlüsselwortargument aufrufen müssen. Dies geschieht normalerweise, wenn es schwierig ist, den Zweck des Arguments ohne den Hinweis durch den Namen des Arguments zu verstehen.

Vergleiche zB sorted(nums, reverse=True)vs. wenn du geschrieben hast sorted(nums, True). Letzteres wäre viel weniger lesbar, daher haben die Python-Entwickler beschlossen, Sie dazu zu bringen, es auf die erstere Weise zu schreiben.

kaya3
quelle
4

Angenommen, Sie haben Funktion:

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

Sie können diese Funktion auf zwei Arten aufrufen:

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

Angenommen, Sie möchten sum, dass die Funktion nur mit Schlüsselwortargumenten aufgerufen wird.

Sie fügen *der Funktionsparameterliste hinzu, um das Ende der Positionsargumente zu markieren.

Also Funktion definiert als:

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

darf nur mit aufgerufen werden sum(1,key=2)

rok
quelle
-1

Ich habe den folgenden Link als sehr hilfreich zu erklären *, *argsund **kwargs:

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

Zusätzlich zu den obigen Antworten habe ich auf der obigen Website (Kredit: https://pythontips.com/author/yasoob008/ ) Folgendes gelernt :

Mit der unten zuerst definierten Demonstrationsfunktion gibt es zwei Beispiele, eines mit *argsund eines mit**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

Auf diese Weise *argskönnen Sie dynamisch eine Liste von Argumenten erstellen, die in der Reihenfolge aufgenommen werden, in der sie **kwargseingegeben werden, während Sie die Übergabe von NAMED-Argumenten ermöglichen und von NAME entsprechend verarbeitet werden können (unabhängig von der Reihenfolge, in der sie eingegeben werden). .

Die Site fährt fort und merkt an, dass die richtige Reihenfolge der Argumente sein sollte:

some_func(fargs,*args,**kwargs)
lb_so
quelle
2
Diese Antwort hat fast nichts mit der Frage zu tun. Es wird sogar eine veraltete Python-Version verwendet, die diese Funktion nicht bietet.
Antti Haapala