Asterisco nudo negli argomenti delle funzioni?


242

Cosa fa un asterisco nudo negli argomenti di una funzione?

Quando ho guardato il modulo pickle , vedo questo:

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

Conosco un singolo e doppio asterisco che precede argomenti (per un numero variabile di argomenti), ma questo non precede nulla. E sono abbastanza sicuro che questo non abbia nulla a che fare con il sottaceto. Questo è probabilmente solo un esempio di ciò che sta accadendo. Ho imparato il suo nome solo quando ho inviato questo all'interprete:

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

Se è importante, sono su Python 3.3.0.


Risposte:


221

Bare *viene utilizzato per forzare il chiamante a utilizzare argomenti con nome, quindi non è possibile definire una funzione con *come argomento quando non si hanno seguenti argomenti di parole chiave.

Vedi questa risposta o la documentazione di Python 3 per maggiori dettagli.


3
Si noti che tutti gli argomenti posizionali (senza nome), incluso *args, devono verificarsi prima di quelli nudi *.
BallpointBen,

4
Si noti inoltre che esiste una sorta di controparte, /, che segna la fine degli argomenti solo posizionali ( stackoverflow.com/questions/28243832/… ).
Stephen,

2
@BallpointBen: *è al posto di *argse viceversa; non possono coesistere in una firma. Ecco perché hanno scelto *; in precedenza, *argsera l'unico modo per forzare argomenti puramente posizionali, e segnava la fine degli argomenti che potevano essere passati in modo posizionale (poiché aveva raccolto tutti gli argomenti posizionali rimanenti, potevano raggiungere i seguenti argomenti denominati). *significa che gli stessi "argomenti posizionali non possono andare oltre qui", ma la mancanza di un nome significa "ma non li accetterò affatto, perché ho scelto di non fornire un posto dove metterli".
ShadowRanger

70

Mentre la risposta originale risponde completamente alla domanda, aggiungendo solo un po 'di informazioni correlate. Il comportamento per il singolo asterisco deriva da PEP-3102. Citando la sezione relativa:

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 inglese semplice, significa che per passare il valore per chiave, è necessario passarlo esplicitamente come key="value".


Oh, questo rende le cose molto più chiare. Quindi in realtà avere un argomento * è come avere un argomento args *, ma dal momento che non lo hai chiamato in alcun modo, il suo unico effetto è probabilmente quello di inghiottire tranquillamente tutti gli argomenti posizionali rimanenti, al fine di forzare gli argomenti rimanenti ad essere parole chiave -solo.
Stephen

11
@Stephen Anche io originariamente pensavo, l'effetto di bare *è quello di inghiottire gli argomenti posizionali rimanenti, ma non è così. Passare ulteriori argomenti posizionali di quanto la funzione si aspetti, dà un errore di questo tipo: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

l'esempio sopra con ** kwargs

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

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

6

Semanticamente, significa che gli argomenti che seguono sono solo parole chiave, quindi riceverai un errore se provi a fornire un argomento senza specificarne il nome. Per esempio:

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

Pragmaticamente, significa che devi chiamare la funzione con un argomento di parole chiave. Di solito viene fatto quando sarebbe difficile capire lo scopo dell'argomento senza il suggerimento dato dal nome dell'argomento.

Confronta ad es. sorted(nums, reverse=True)Vs. se hai scritto sorted(nums, True). Quest'ultimo sarebbe molto meno leggibile, quindi gli sviluppatori di Python hanno scelto di farti scrivere nel primo modo.


4

Supponiamo di avere una funzione:

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

Puoi chiamare questa funzione in 2 modi:

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

Supponiamo che tu voglia che la funzione sumvenga chiamata usando solo argomenti di parole chiave

Si aggiunge *all'elenco dei parametri della funzione per contrassegnare la fine degli argomenti posizionali.

Quindi funzione definita come:

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

può essere chiamato solo usando sum(1,key=2)


-1

Ho trovato il seguente Link per essere molto utile per spiegare *, *argse **kwargs:

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

In sostanza, oltre alle risposte sopra, ho imparato dal sito sopra (credito: https://pythontips.com/author/yasoob008/ ) quanto segue:

Con la funzione dimostrativa definita prima sotto, ci sono due esempi, uno con *argse uno con**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

Quindi *argspermette di costruire dinamicamente un elenco di argomenti che verranno presi nell'ordine in cui sono alimentati, che **kwargspuò consentire il passaggio di argomenti denominati, e può essere elaborato da NAME conseguenza (indipendentemente dall'ordine in cui vengono alimentati) .

Il sito continua, osservando che il corretto ordinamento degli argomenti dovrebbe essere:

some_func(fargs,*args,**kwargs)

2
Questa risposta non ha quasi nulla a che fare con la domanda. Sta persino usando una versione obsoleta di Python che non ha la funzione.
Antti Haapala,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.