2012-12-16 31 views
6

Trovato cosa interessante in Python (2.7) che non è mai stato menzionato prima.Elenco estendere comportamento strano

questo:

a = [] 
a += "a" 

funziona e il risultato è il seguente:

>>> a 
>>> ["a"] 

Ma

a = [] 
a = a + "a" 

>>> TypeError: can only concatenate list (not "str") to list 

Qualcuno può spiegare perché? Grazie per le tue risposte.

+0

'+' e '+ =' sono operazioni diverse anche se sembrano fare lo stesso in molte situazioni. –

+1

'+ =' si comporta come extend() negli elenchi python (inplace add) e l'altro è chiamato binary add. –

risposta

11

Python distingue tra gli operatori + e += e fornisce ganci separati per questi; __add__ e __iadd__. Il tipo list() fornisce semplicemente un'implementazione diversa per quest'ultimo.

È più efficiente per gli elenchi implementarli separatamente; __add__ deve restituire un elenco completamente nuovo, mentre __iadd__ può solo estendere self quindi restituire self.

Nel codice C, __iadd__ è implementata tramite list_inplace_concat(), che richiede semplicemente listextend(), o, nel codice pitone, [].extend(). Quest'ultimo prende qualsiasi sequenza, in base alla progettazione.

Il metodo __add__ d'altra parte, rappresentato in C da list_concat, accetta solo uno list come input, probabilmente per motivi di efficienza; può scorrere direttamente sull'array C interno e copiare gli elementi nel nuovo elenco.

In conclusione, la ragione __iadd__ accetta qualsiasi sequenza è perché quando PEP 203 (l'Augmented Aggiungi proposta) è stato implementato, per le liste è stato più semplice solo per riutilizzare il metodo .extend().

+0

Grazie, Martijn, questa è la risposta che stavo cercando. – alexvassel

9

Se a è un elenco, a + x funziona solo se x è anche la lista, mentre a += x funziona per qualsiasi iterabile x.

Quanto segue potrebbe aiutare a capire è:

In [4]: a = [] 

In [5]: a += "abc" 

In [6]: a 
Out[6]: ['a', 'b', 'c'] 

La chiave è che "a" e "abc" sono iterabile, che è ciò che permette il loro utilizzo sul lato destro della +=.

Questo non funziona per + poiché quest'ultimo richiede che entrambi gli operandi siano dello stesso tipo (vedere manual).

Per scrivere la stessa cosa usando +, è necessario espandere l'iterabile:

In [7]: a = [] 

In [8]: a = a + list("abc") 

In [9]: a 
Out[9]: ['a', 'b', 'c'] 

In altre parole, += è più ampio di + quando applicato alle liste.

+0

La domanda riguarda la * differenza * tra 'lst + = iterable' e' lst + iterable'. –

+0

Non spiega perché non sia possibile concatenare un elenco e un iterabile. –

+0

@MartijnPieters: sicuro. Vedi l'ultima risposta. – NPE