In Python, qual è la differenza tra ".append ()" e "+ = []"?


Risposte:


161

Nel tuo caso l'unica differenza sono le prestazioni: l'append è due volte più veloce.

Python 3.0 (r30:67507, Dec  3 2008, 20:14:27) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> timeit.Timer('s.append("something")', 's = []').timeit()
0.20177424499999999
>>> timeit.Timer('s += ["something"]', 's = []').timeit()
0.41192320500000079

Python 2.5.1 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> timeit.Timer('s.append("something")', 's = []').timeit()
0.23079359499999999
>>> timeit.Timer('s += ["something"]', 's = []').timeit()
0.44208112500000141

In generale, il caso appendaggiungerà un elemento alla lista, mentre +=copierà tutti gli elementi della lista di destra nella lista di sinistra.

Aggiornamento: analisi delle prestazioni

Confrontando i bytecode possiamo presumere che la appendversione sprechi cicli in LOAD_ATTR+ CALL_FUNCTIONe + = versione - in BUILD_LIST. Apparentemente BUILD_LISTsupera LOAD_ATTR+ CALL_FUNCTION.

>>> import dis
>>> dis.dis(compile("s = []; s.append('spam')", '', 'exec'))
  1           0 BUILD_LIST               0
              3 STORE_NAME               0 (s)
              6 LOAD_NAME                0 (s)
              9 LOAD_ATTR                1 (append)
             12 LOAD_CONST               0 ('spam')
             15 CALL_FUNCTION            1
             18 POP_TOP
             19 LOAD_CONST               1 (None)
             22 RETURN_VALUE
>>> dis.dis(compile("s = []; s += ['spam']", '', 'exec'))
  1           0 BUILD_LIST               0
              3 STORE_NAME               0 (s)
              6 LOAD_NAME                0 (s)
              9 LOAD_CONST               0 ('spam')
             12 BUILD_LIST               1
             15 INPLACE_ADD
             16 STORE_NAME               0 (s)
             19 LOAD_CONST               1 (None)
             22 RETURN_VALUE

Possiamo migliorare ulteriormente le prestazioni rimuovendo il LOAD_ATTRsovraccarico:

>>> timeit.Timer('a("something")', 's = []; a = s.append').timeit()
0.15924410999923566

12
+1: questo è molto interessante. Uso comunque append, perché risulta in un codice più chiaro. Ma non mi rendevo conto che ci fosse una differenza di prestazioni. Semmai, mi sarei aspettato che append fosse più lento, poiché è una chiamata di funzione garantita, mentre presumevo che + = sarebbe stato ottimizzato ulteriormente.
DNS

2
Non c'è anche una differenza funzionale? Ad esempio, sia a = [] , b = [4,5,6] , qui se fai c = a. Appendi (b) allora c sarebbe una lista di lista [[4,5,6]] mentre c + = b ; porterebbe a una semplice lista c = [4,5,6] .
rph

solo per mettere le cose in chiaro: + = offre prestazioni migliori rispetto all'estensione o all'aggiunta fintanto che l'input è nel formato corretto. Ciò che richiede tempo nell'esempio corrente è la creazione dell'elenco ['qualcosa']. + = è circa il 15% più veloce
Joe

@ Joe Se stai confrontando appendvs +=, devi includere la creazione dell'elenco come parte della misurazione. Altrimenti sarebbe una domanda diversa ( extendvs +=).
jamesdlin

@jamesdlin yup! Ma è facile sbagliarsi se non lo sai già. Un po 'di precisione in più non ha mai fatto male a nessuno, giusto?
Joe,

48

Nell'esempio che hai fornito, non c'è differenza, in termini di output, tra appende +=. Ma c'è una differenza tra appende +(che la domanda originariamente posta).

>>> a = []
>>> id(a)
11814312
>>> a.append("hello")
>>> id(a)
11814312

>>> b = []
>>> id(b)
11828720
>>> c = b + ["hello"]
>>> id(c)
11833752
>>> b += ["hello"]
>>> id(b)
11828720

Come puoi vedere, appende +=avere lo stesso risultato; aggiungono l'elemento all'elenco, senza produrre un nuovo elenco. Utilizzando +aggiunge i due elenchi e produce un nuovo elenco.


V'è differenza tra append e + =.
Constantin

3
C'è il fatto che appendaggiunge una voce alla lista, mentre + = ne aggiunge tante quante sono nell'altra lista (cioè gli alias a extend). Ma lo sa già, a giudicare dal modo in cui è stata scritta la domanda. C'è qualche altra differenza che mi manca?
DNS

1
C'è una differenza perché un compito aumentato introduce il rebinding (spiegazione nella mia risposta).
bobince

42
>>> a=[]
>>> a.append([1,2])
>>> a
[[1, 2]]
>>> a=[]
>>> a+=[1,2]
>>> a
[1, 2]

Vedi che append aggiunge un singolo elemento alla lista, che può essere qualsiasi cosa. +=[]si unisce alle liste.


2
Votare questo perché questa è una distinzione importante tra i due. Buon lavoro.

31

+ = è un compito. Quando lo usi stai davvero dicendo 'some_list2 = some_list2 + [' qualcosa ']'. Le assegnazioni implicano il rebinding, quindi:

l= []

def a1(x):
    l.append(x) # works

def a2(x):
    l= l+[x] # assign to l, makes l local
             # so attempt to read l for addition gives UnboundLocalError

def a3(x):
    l+= [x]  # fails for the same reason

L'operatore + = dovrebbe anche creare normalmente un nuovo oggetto lista come normalmente lista + lista:

>>> l1= []
>>> l2= l1

>>> l1.append('x')
>>> l1 is l2
True

>>> l1= l1+['x']
>>> l1 is l2
False

Tuttavia in realtà:

>>> l2= l1
>>> l1+= ['x']
>>> l1 is l2
True

Questo perché gli elenchi Python implementano __iadd __ () per creare un cortocircuito dell'assegnazione aumentata + = e chiamare list.extend () invece. (È un po 'strano questo: di solito fa quello che intendevi, ma per motivi confusi.)

In generale, se stai aggiungendo / estendendo un elenco esistente e desideri mantenere il riferimento allo stesso elenco (invece di crearne uno nuovo), è meglio essere espliciti e attenersi all'append () / extent () metodi.


21
 some_list2 += ["something"]

è effettivamente

 some_list2.extend(["something"])

per un valore, non c'è differenza. La documentazione afferma che:

s.append(x) uguale allo s[len(s):len(s)] = [x]
s.extend(x) stesso dis[len(s):len(s)] = x

Quindi ovviamente s.append(x)è uguale as.extend([x])


s.append prende un tipo arbitrario e lo aggiunge alla lista; È una vera appendice. s.extend accetta un iterabile (di solito una lista) e fonde l'iterabile in s, modificando gli indirizzi di memoria di s. Questi non sono gli stessi.
W4t3randWind

9

La differenza è che la concatenazione appiattirà l'elenco risultante, mentre append manterrà intatti i livelli:

Quindi ad esempio con:

myList = [ ]
listA = [1,2,3]
listB = ["a","b","c"]

Usando append, ti ritroverai con un elenco di elenchi:

>> myList.append(listA)
>> myList.append(listB)
>> myList
[[1,2,3],['a',b','c']]

Usando invece la concatenazione, ti ritroverai con un elenco piatto:

>> myList += listA + listB
>> myList
[1,2,3,"a","b","c"]

5

I test delle prestazioni qui non sono corretti:

  1. Non dovresti eseguire il profilo solo una volta.
  2. Se si confronta append con + = [] il numero di volte si dovrebbe dichiarare append come funzione locale.
  3. i risultati temporali sono diversi nelle diverse versioni di Python: 64 e 32 bit

per esempio

timeit.Timer ('for i in xrange (100): app (i)', 's = []; app = s.append'). timeit ()

buoni test possono essere trovati qui: http://markandclick.com/1/post/2012/01/python-list-append-vs.html


tuttavia, il test + = in quella pagina usa += [one_var]. Se omettiamo di creare elenchi, + = diventa l'opzione più veloce.
Joe

3

Oltre agli aspetti descritti nelle altre risposte, append e + [] hanno comportamenti molto diversi quando cerchi di creare un elenco di elenchi.

>>> list1=[[1,2],[3,4]]
>>> list2=[5,6]
>>> list3=list1+list2
>>> list3
[[1, 2], [3, 4], 5, 6]
>>> list1.append(list2)
>>> list1
[[1, 2], [3, 4], [5, 6]]

list1 + ["5", "6"] aggiunge "5" e "6" a list1 come singoli elementi. list1.append (['5', '6']) aggiunge l'elenco ['5', '6'] a list1 come un singolo elemento.


2

Il comportamento di rebinding menzionato in altre risposte è importante in determinate circostanze:

>>> a = ([],[])
>>> a[0].append(1)
>>> a
([1], [])
>>> a[1] += [1]
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

Questo perché l'assegnazione aumentata si ricollega sempre, anche se l'oggetto è stato mutato sul posto. Il rebinding qui sembra essere a[1] = *mutated list*, che non funziona per le tuple.


0

facciamo prima un esempio

list1=[1,2,3,4]
list2=list1     (that means they points to same object)

if we do 
list1=list1+[5]    it will create a new object of list
print(list1)       output [1,2,3,4,5] 
print(list2)       output [1,2,3,4]

but if we append  then 
list1.append(5)     no new object of list created
print(list1)       output [1,2,3,4,5] 
print(list2)       output [1,2,3,4,5]

extend(list) also do the same work as append it just append a list instead of a 
single variable 

0

Il metodo append () aggiunge un singolo elemento all'elenco esistente

some_list1 = []
some_list1.append("something")

Quindi qui il some_list1 verrà modificato.

aggiornato:

Considerando che si usa + per combinare gli elementi delle liste (più di un elemento) nella lista esistente simile all'estensione (come corretto da Flux ).

some_list2 = []
some_list2 += ["something"]

Quindi qui il some_list2 e ["qualcosa"] sono i due elenchi che vengono combinati.


1
Questo è sbagliato. +=non restituisce un nuovo elenco. La FAQ sulla programmazione dice: "... per le liste, __iadd__equivale a richiamare extendla lista e restituire la lista. Ecco perché diciamo che per le liste, +=è una" scorciatoia "per list.extend". Puoi anche vederlo da solo nel codice sorgente di CPython: github.com/python/cpython/blob/v3.8.2/Objects/…
Flux

0

"+" non modifica l'elenco

.Append () muta la vecchia lista

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.