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

  1. Come è gestito internamente nell'interprete?
  2. influisce prestazioni a tutti? E 'veloce o lento?
  3. Quando è utile e quando non è vero?
  4. dovrebbe essere utilizzato in una dichiarazione di funzione o in una chiamata?
È stato utile?

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})".

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top