Che cosa significa l'operatore stella? [duplicare]
-
05-10-2019 - |
Domanda
Questa domanda ha già una risposta qui:
Che cosa fa l'operatore media *
in Python, come ad esempio in codice come zip(*x)
o f(**k)
?
- Come è gestito internamente nell'interprete?
- influisce prestazioni a tutti? E 'veloce o lento?
- Quando è utile e quando non è vero?
- dovrebbe essere utilizzato in una dichiarazione di funzione o in una chiamata?
Soluzione
Il singolo *
stelle spacchetta la sequenza / raccolta in argomenti posizionali, in modo da poter fare questo:
def sum(a, b):
return a + b
values = (1, 2)
s = sum(*values)
Questo decomprimere il tupla scopo di essere eseguito in realtà come:
s = sum(1, 2)
Il doppio **
stella fa lo stesso, solo con un dizionario e gli argomenti così denominati:
values = { 'a': 1, 'b': 2 }
s = sum(**values)
È inoltre possibile combinare:
def sum(a, b, c, d):
return a + b + c + d
values1 = (1, 2)
values2 = { 'c': 10, 'd': 15 }
s = sum(*values1, **values2)
eseguirà come:
s = sum(1, 2, c=10, d=15)
Si veda anche la sezione 4.7.4 - Liste Apertura della confezione di argomenti della documentazione Python.
Inoltre è possibile definire funzioni per prendere *x
e **y
argomenti, questo permette una funzione di accettare un numero qualsiasi di argomenti posizionali e / o nome che non sono specificamente indicati nella dichiarazione.
Esempio:
def sum(*values):
s = 0
for v in values:
s = s + v
return s
s = sum(1, 2, 3, 4, 5)
o con **
:
def get_a(**values):
return values['a']
s = get_a(a=1, b=2) # returns 1
questo può consentire di specificare un gran numero di parametri opzionali senza la necessità di dichiararli.
E ancora, è possibile combinare:
def sum(*values, **options):
s = 0
for i in values:
s = s + i
if "neg" in options:
if options["neg"]:
s = -s
return s
s = sum(1, 2, 3, 4, 5) # returns 15
s = sum(1, 2, 3, 4, 5, neg=True) # returns -15
s = sum(1, 2, 3, 4, 5, neg=False) # returns 15
Altri suggerimenti
Un piccolo punto: questi non sono gli operatori. Gli operatori sono usati nelle espressioni per creare nuovi valori dai valori esistenti (1 + 2 diventa 3, per esempio. Il * e ** qui sono parte della sintassi delle dichiarazioni di funzione e le chiamate.
Ho trovato questo particolarmente utile per quando si vuole 'negozio' una chiamata di funzione.
Per esempio, supponiamo di avere alcuni test di unità per una funzione di 'add':
def add(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
Non c'è altro modo per chiamare add, altro che fare manualmente qualcosa come add (test [0], prova [1]), che è brutto. Inoltre, se ci sono un numero variabile di variabili, il codice potrebbe diventare piuttosto brutta con tutte le se-dichiarazioni si avrebbe bisogno.
Un altro posto questo è utile è per la definizione di oggetti di fabbrica (oggetti che creano oggetti per voi). Supponiamo di avere una classe di fabbrica, che rende gli oggetti macchina e li restituisce. Si potrebbe fare in modo che myFactory.make_car ( 'rosso', 'bmw', '335ix') crea Car ( 'rosso', 'bmw', '335ix'), poi lo restituisce.
def make_car(*args):
return Car(*args)
Questo è utile anche quando si desidera chiamare un costruttore della superclasse.
Si chiama la sintassi di chiamata estesa. Dal documentazione :
Se la sintassi * espressione appare nella chiamata di funzione, l'espressione deve essere valutata come una sequenza. Elementi di questa sequenza sono trattati come se fossero argomenti posizionali aggiuntivi; se ci sono argomenti posizionali x1, ..., valuta xN ed espressione a una sequenza y1, ..., yM, questo è equivalente ad una chiamata con M + N argomenti posizionali x1, ..., xN, y1,. .., yM.
e
Se la sintassi ** appare espressione nella chiamata di funzione, espressione devono valutare ad una mappatura, i cui contenuti sono trattati come argomenti chiave aggiuntivi. Nel caso di una parola chiave che compare in entrambe espressione e come argomento esplicito parola chiave, un'eccezione TypeError viene sollevata.
In una chiamata di funzione della singola stella diventa una lista in argomenti separati (ad esempio zip(*x)
è la stessa di zip(x1,x2,x3)
se x=[x1,x2,x3]
) e la doppia stella si trasforma un dizionario in argomento chiave separate (per esempio f(**k)
è lo stesso di f(x=my_x, y=my_y)
se k = {'x':my_x, 'y':my_y}
.
In una definizione di funzione è il contrario: il singolo stella diventa un numero arbitrario di argomenti in una lista, e la doppia partenza si trasforma un numero arbitrario di argomenti a parola chiave in un dizionario. Per esempio. mezzi def foo(*x)
"foo richiede un numero arbitrario di argomenti e saranno accessibili attraverso la lista x (cioè se l'utente chiama foo(1,2,3)
, x
sarà [1,2,3]
)" e mezzi def bar(**k)
"bar prende un numero arbitrario di argomenti chiave e saranno accessibili attraverso il k dizionario (cioè se l'utente chiama bar(x=42, y=23)
, k
sarà {'x': 42, 'y': 23}
)".