Was ist in Python der Unterschied zwischen ".append ()" und "+ = []"?


121

Was ist der Unterschied zwischen:

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

und

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

3
anhängen, wenn für einen einzelnen Artikel. Vielleicht meinst du extend.
Hasen


Antworten:


159

In Ihrem Fall ist der einzige Unterschied die Leistung: Das Anhängen ist doppelt so schnell.

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

Im Allgemeinen appendwird der Liste ein Element hinzugefügt, während alle Elemente der Liste auf der rechten Seite in die Liste auf der linken Seite +=kopiert werden .

Update: Perf-Analyse

Beim Vergleich von Bytecodes können wir davon ausgehen, dass die appendVersion Zyklen in LOAD_ATTR+ CALL_FUNCTIONund + = version - in verschwendet BUILD_LIST. Anscheinend BUILD_LISTüberwiegt 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

Wir können die Leistung noch weiter verbessern, indem wir den LOAD_ATTROverhead entfernen :

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

12
+1: Das ist sehr interessant. Ich benutze sowieso append, weil es zu klarerem Code führt. Aber ich wusste nicht, dass es einen Leistungsunterschied gibt. Wenn überhaupt, hätte ich erwartet, dass das Anhängen langsamer ist, da es sich um einen garantierten Funktionsaufruf handelt, während ich davon ausgegangen bin, dass + = weiter optimiert wird.
DNS

2
Gibt es nicht auch einen funktionalen Unterschied? Zum Beispiel sei a = [] , b = [4,5,6] . Wenn Sie hier c = a.append (b) ausführen, ist c eine Liste der Liste [[4,5,6]], während c + = b ; würde zu einer einfachen Liste führen c = [4,5,6] .
rph

Nur um die Dinge klar zu stellen: + = bietet eine bessere Leistung als Erweitern oder Anhängen, solange Ihre Eingabe im richtigen Format vorliegt. Was im aktuellen Beispiel Zeit braucht, ist die Erstellung der Liste ['etwas']. + = ist ungefähr 15% schneller
Joe

@Joe Wenn Sie appendvs vergleichen +=, müssen Sie die Erstellung der Liste als Teil der Messung einbeziehen . Sonst wäre es eine andere Frage ( extendvs +=).
Jamesdlin

@ Jamesdlin yup! Aber es ist leicht, sich zu irren, wenn Sie das nicht bereits wissen. Ein bisschen zusätzliche Präzision hat noch nie jemanden verletzt, oder?
Joe

47

In dem von Ihnen angegebenen Beispiel gibt es keinen Unterschied in Bezug auf die Ausgabe zwischen appendund +=. Aber es gibt einen Unterschied zwischen appendund +(worüber die Frage ursprünglich gestellt wurde).

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

Wie Sie sehen können appendund +=das gleiche Ergebnis haben; Sie fügen das Element der Liste hinzu, ohne eine neue Liste zu erstellen. Mit +fügt werden die beiden Listen hinzugefügt und eine neue Liste erstellt.


Es gibt einen Unterschied zwischen Anhängen und + =.
Constantin

3
Es gibt die Tatsache, dass appendein Eintrag zur Liste hinzugefügt wird, während + = so viele hinzufügt, wie in der anderen Liste vorhanden sind (dh Aliase zu extend). Aber er / sie weiß das schon, gemessen an der Art und Weise, wie die Frage geschrieben wurde. Gibt es einen anderen Unterschied, den ich vermisse?
DNS

1
Es gibt einen Unterschied, weil eine erweiterte Aufgabe das erneute Binden einführt (Erklärung in meiner Antwort).
Bobince

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

Sehen Sie, dass das Anhängen der Liste ein einzelnes Element hinzufügt, das alles sein kann. +=[]schließt sich den Listen an.


2
Stimmen Sie ab, weil dies eine wichtige Unterscheidung zwischen den beiden ist. Gute Arbeit.

31

+ = ist eine Aufgabe. Wenn Sie es verwenden, sagen Sie wirklich 'some_list2 = some_list2 + [' etwas ']'. Zuweisungen beinhalten das erneute Binden, also:

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

Der Operator + = sollte normalerweise auch ein neues Listenobjekt erstellen, wie es list + list normalerweise tut:

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

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

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

In Wirklichkeit jedoch:

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

Dies liegt daran, dass Python-Listen __iadd __ () implementieren , um einen + = erweiterten Zuweisungskurzschluss zu erstellen und stattdessen list.extend () aufzurufen. (Es ist ein bisschen eine seltsame Warze: Sie macht normalerweise das, was Sie gemeint haben, aber aus verwirrenden Gründen.)

Wenn Sie eine vorhandene Liste anhängen / erweitern und den Verweis auf dieselbe Liste beibehalten möchten (anstatt eine neue zu erstellen), ist es im Allgemeinen am besten, explizit zu sein und bei append () / extens () zu bleiben. Methoden.


21
 some_list2 += ["something"]

ist eigentlich

 some_list2.extend(["something"])

Für einen Wert gibt es keinen Unterschied. In der Dokumentation heißt es:

s.append(x) gleich wie s[len(s):len(s)] = [x]
s.extend(x) gleich wies[len(s):len(s)] = x

Somit ist offensichtlich s.append(x)dasselbe wies.extend([x])


s.append nimmt einen beliebigen Typ und fügt ihn der Liste hinzu; Es ist ein wahrer Anhang. s.extend nimmt eine iterable (normalerweise eine Liste) und führt die iterable in s zusammen, wobei die Speicheradressen von s geändert werden. Diese sind nicht gleich.
W4t3randWind

9

Der Unterschied besteht darin, dass durch Verketten die resultierende Liste reduziert wird , während durch Anhängen die Ebenen intakt bleiben:

So zum Beispiel mit:

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

Wenn Sie Anhängen verwenden, erhalten Sie eine Liste mit Listen:

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

Wenn Sie stattdessen verketten verwenden, erhalten Sie eine flache Liste:

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

5

Die Leistungstests hier sind nicht korrekt:

  1. Sie sollten das Profil nicht nur einmal ausführen.
  2. Wenn Sie append mit + = [] vergleichen, sollten Sie append als lokale Funktion deklarieren.
  3. Die Zeitergebnisse sind bei verschiedenen Python-Versionen unterschiedlich: 64 und 32 Bit

z.B

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

Gute Tests finden Sie hier: http://markandclick.com/1/post/2012/01/python-list-append-vs.html


Trotzdem werden die + = Tests auf dieser Seite verwendet += [one_var]. Wenn wir das Erstellen von Listen weglassen, wird + = die schnellste Option.
Joe

3

Zusätzlich zu den in den anderen Antworten beschriebenen Aspekten verhalten sich Anhängen und + [] sehr unterschiedlich, wenn Sie versuchen, eine Liste von Listen zu erstellen.

>>> 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'] fügt der Liste1 '5' und '6' als einzelne Elemente hinzu. list1.append (['5', '6']) fügt die Liste ['5', '6'] als einzelnes Element zur Liste1 hinzu.


2

Das in anderen Antworten erwähnte Rückbindungsverhalten spielt unter bestimmten Umständen eine Rolle:

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

Dies liegt daran, dass die erweiterte Zuweisung immer wieder neu bindet, selbst wenn das Objekt an Ort und Stelle mutiert wurde. Das erneute Binden hier ist zufällig a[1] = *mutated list*, was bei Tupeln nicht funktioniert.


0

Nehmen wir zuerst ein Beispiel

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

Die Methode append () fügt der vorhandenen Liste ein einzelnes Element hinzu

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

Hier wird also some_list1 geändert.

Aktualisiert:

Verwenden Sie +, um die Elemente von Listen (mehr als ein Element) in der vorhandenen Liste zu kombinieren, ähnlich der Erweiterung (wie von Flux korrigiert ).

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

Hier sind also some_list2 und ["etwas"] die beiden Listen, die kombiniert werden.


1
Das ist falsch. +=gibt keine neue Liste zurück. In den häufig gestellten Fragen zur Programmierung heißt es: "... für Listen __iadd__entspricht dem Aufrufen extendder Liste und dem Zurückgeben der Liste. Deshalb sagen wir, dass für Listen +=eine" Abkürzung "für list.extend" ist. Sie können dies auch im CPython-Quellcode selbst sehen: github.com/python/cpython/blob/v3.8.2/Objects/…
Flux

0

„+“ Nicht mutiert die Liste

.append () mutiert die alte Liste

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.