2013-10-21 20 views
5

Per esempio in questo codice:Cosa significa * = in python?

def product(list): 
    p =1 
    for i in list: 
     p *= i 
    return p 

Ho trovato questo codice, ma ho bisogno di essere in grado di spiegare ogni parte di esso.

+1

Denominazione di un 'list' variabile è una pratica di codifica male - ha la precedenza il built-in. – iCodez

risposta

4

Solitamente p *= i corrisponde a p = p * i.

A volte può essere diverso, e penso che le spiegazioni già postato non sono sufficientemente chiare per questo, quindi:

Può essere diverso quando p è un oggetto mutabile. In tal caso, sul posto *= è possibile modificare l'oggetto originale anziché crearne uno nuovo. Confrontare ciò che accade a q in ciascuno di questi:

>>> p = q = [2] 
>>> p *= 5 
>>> p 
[2, 2, 2, 2, 2] 
>>> q 
[2, 2, 2, 2, 2] 

>>> p = q = [2] 
>>> p = p * 5 
>>> p 
[2, 2, 2, 2, 2] 
>>> q 
[2] 

Se anche può essere diverso quando p è un complesso un'espressione con effetti collaterali come sul posto versione valuta solo sottoespressioni volta. Così, per esempio:

aList[randint(0, 5)] *= 3 

non è lo stesso di:

aList[randint(0, 5)] = aList[randint(0, 5)] * 3 
9

E 'una scorciatoia per

p = p * i 

E' analogo a quello più frequente p += i

+4

Questo è vero per questo particolare pezzo di codice, ma in generale si tratta di un po 'di eccessiva semplificazione. – georg

5

Tratto da primo risultato in google:

moltiplicarsi e operatore di assegnazione, si moltiplica operando di destra con l'operando di sinistra e assegnare il risultato all'operando di sinistra

*= è lo stesso che dire p = p * i.

This link contiene un elenco di tutti gli operatori nelle loro varie, meravigliose combinazioni.

Esempio

Una spiegazione pseudo-codice del codice è il seguente:

assume list := {4, 6, 5, 3, 5, 1} 
p := 1. 

for(each number in list) 
    p = the current value of p * the current number. 
    // So: 1 * 4, 4 * 6, 24 * 5, 120 * 3... 

return p. 
+0

+1 ottima risposta: D –

4

Non è esattamente lo stesso di p = p * i:

>>> class A(int): 
...  def __imul__(self, item): 
...   print '__imul__ is running!' 
...  
...  def __mul__(self, item): 
...   print '__mul__ is running!' 
>>> mynumber = A(10) 
>>> mynumber *= 5 
__imul__ is running! 
>>> mynumber = A(10) 
>>> mynumber * 5 
__mul__ is running! 

Tuttavia l'uscita è per lo più lo stesso, quindi probabilmente dovresti trattarlo così

+0

come può __mul__ essere in esecuzione nella tua ultima riga senza una moltiplicazione? – ychaouche

+0

@ychaouche oops mi dispiace che si tratti di un errore da parte mia – TerryA

+0

@Haidro Questo è stato un po 'troppo complicato per un principiante: P –

4

L'idea alla base dell'operatore a *= b equivale a a = a * b. Nella maggior parte dei casi (come nel tuo) farà esattamente questo, quindi moltiplica una variabile con un valore e memorizza nuovamente il risultato nella variabile.

La notazione che utilizza *= potrebbe essere più veloce (a seconda delle classi coinvolte) ed è, in ogni caso, la versione più chiara, quindi dovrebbe essere favorita. Il suo vantaggio principale indica se la variabile a è di per sé già un'espressione complessa come myGiantValueField[f(42)].getValue()[3]:

myGiantValueField[f(42)].getValue()[3] = myGiantValueField[f(42)].getValue()[3] * 3 

è certamente meno leggibile e causa di un codice raddoppio più inclini a fissaggio-errori di

myGiantValueField[f(42)].getValue()[3] *= 3 

In generale, tuttavia, l'operatore *= chiama il metodo __imul__() della variabile a e passa l'argomento b, quindi significa esattamente lo stesso di a.__imul__(b) (che non è così intuitivo).

Perché potrebbe esserci una differenza tra a = a * b e a *= b? Tre ragioni vengono due volte contemporaneamente, ma potrebbero essercene altre.

  1. Una classe potrebbe implementare solo l'operatore *= (così a * b potrebbe essere indefinito sebbene a *= b esiste) a causa di aspetti delle prestazioni. Moltiplicare un valore molto grande (ad esempio una matrice gigante) con un numero a volte è meglio farlo sul posto per evitare di dover allocare memoria per il risultato (che potrebbe subito dopo il calcolo essere copiato nella variabile originale dall'assegnazione). Quello a = a * b è internamente come tmp = a * b e a = tmp.
  2. Una classe potrebbe trovare il suo uso non intuitivo utilizzando la moltiplicazione diretta, quindi potrebbe non essere implementato l'operatore *. Un esempio potrebbe essere una classe che rappresenta il volume dell'altoparlante del computer. Raddoppiare il volume potrebbe avere senso (volumeKnob *= 2) mentre il calcolo senza l'uso (assegnazione) non è raccomandato (x = volumeKnob * 2? ← non ha senso in quanto non fa nulla).
  3. Se il tipo del risultato della moltiplicazione differisce dal tipo di a, non mi aspetto o consiglio di implementare l'operatore *= in quanto sarebbe fuorviante. Un esempio potrebbe essere se a e b sono vettori il cui risultato di moltiplicazione sarebbe una matrice (o un numero). Il nome __imul__ suggerisce già che è pensato per essere applicato in modo iterativo, i. e. più di una volta. Ma se il tipo a è cambiato, questo sarebbe problematico.