Python'da ".append ()" ve "+ = []" arasındaki fark nedir?


122

Arasındaki fark nedir:

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

ve

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

3
tek bir öğe için ise ekleyin. belki demek istiyorsun extend.
hasen


Yanıtlar:


161

Sizin durumunuz için tek fark performanstır: Ekleme iki kat daha hızlıdır.

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

Genel durumda appendlisteye bir öğe eklenirken , sağ taraftaki listenin tüm öğeleri sol taraftaki listeye +=kopyalanır .

Güncelleme: performans analizi

Bayt kodlarını karşılaştırarak, appendsürümün LOAD_ATTR+ CALL_FUNCTIONve + = sürüm - içinde döngüleri boşa harcadığını varsayabiliriz BUILD_LIST. Görünüşe göre + BUILD_LISTağır basıyor .LOAD_ATTRCALL_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

LOAD_ATTRGenel giderleri kaldırarak performansı daha da artırabiliriz :

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

12
+1: Bu çok ilginç. Yine de ekleme kullanıyorum, çünkü daha net bir kodla sonuçlanıyor. Ama bir performans farkı olduğunu fark etmemiştim. Bir şey olursa, eklemenin daha yavaş olmasını beklerdim, çünkü bu garantili bir işlev çağrısı iken, + = daha fazla optimize edileceğini varsaydım.
DNS

2
İşlevsel bir fark da yok mu? Örneğin a = [] , b = [4,5,6] olsun , burada c = a.append (b) yaparsanız c + [[4,5,6]] listesinin bir listesi olurken c + = b ; basit bir listeye yol açar c = [4,5,6] .
rph

sadece işleri yoluna koymak için: + =, girişiniz doğru formatta olduğu sürece genişletme veya eklemeden daha iyi bir performans verir. Mevcut örnekte zaman alan, ['bir şeyler'] listesinin oluşturulmasıdır. + = yaklaşık% 15 daha hızlı
Joe

Eğer karşılaştırıyorsanız @Joe appendvs +=, o zaman gerekir ölçüm parçası olarak listenin oluşturulmasını içermektedir. Aksi takdirde, farklı bir soru olurdu ( extendvs +=).
jamesdlin

@jamesdlin yup! Ancak bunu zaten bilmiyorsanız yanılmak kolaydır. Biraz daha fazla hassasiyet kimseye zarar vermez, değil mi?
Joe

48

Verdiğin örnekte, çıkış bakımından, aralarında hiçbir fark yoktur appendve +=. Ancak appendve arasında bir fark vardır +(soru başlangıçta sorulmuştur).

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

Olarak görmek, olabilir appendve +=aynı sonucu var; yeni bir liste oluşturmadan öğeyi listeye eklerler. Kullanmak +iki listeyi ekler ve yeni bir liste oluşturur.


Orada bir ekleme yapılması ve + = arasındaki fark.
Constantin

3
Aslında var appenddiğer listede (yani diğer adlar için olduğu gibi + = birçok olarak ekler ederken, listeye bir giriş ekler extend). Ama sorunun yazılma şekline bakarak bunu zaten biliyor. Kaçırdığım başka bir fark var mı?
DNS

1
Bir fark var çünkü artırılmış bir ödev yeniden bağlama (cevabımda açıklama) getiriyor.
bobince

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

Eklemenin listeye tek bir öğe eklediğini görün, bu herhangi bir şey olabilir. +=[]listelere katılır.


2
Buna oy vermek, çünkü bu ikisi arasında önemli bir ayrım. İyi iş.

31

+ = bir atamadır. Bunu kullandığınızda gerçekten 'bir_list2 = bir_list2 + [' bir şey ']' diyorsunuz. Ödevler yeniden bağlamayı içerir, bu nedenle:

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

+ = Operatörü ayrıca normalde list + list'in normalde yaptığı gibi yeni bir liste nesnesi oluşturmalıdır:

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

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

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

Ancak gerçekte:

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

Bunun nedeni, Python listelerinin + = artırılmış atama kısa devre yapmak için __iadd __ () uygulaması ve bunun yerine list.extend () işlevini çağırmasıdır. (Bu biraz garip bir siğildir: genellikle ne demek istediğinizi yapar, ancak kafa karıştırıcı nedenlerle.)

Genel olarak, mevcut bir listeyi eklerseniz / genişletirseniz ve referansı aynı listeye tutmak istiyorsanız (yenisini yapmak yerine), en iyisi açık olmak ve append () / Extend () 'e bağlı kalmaktır. yöntemleri.


21
 some_list2 += ["something"]

aslında

 some_list2.extend(["something"])

tek bir değer için fark yoktur. Belgeler şunu belirtir:

s.append(x) aynı s[len(s):len(s)] = [x]
s.extend(x) şekilde aynıs[len(s):len(s)] = x

Böylece açıkça s.append(x)aynıdırs.extend([x])


s.append rastgele bir tür alır ve bunu listeye ekler; Bu gerçek bir eklenti. s.extend, yinelenebilir (genellikle bir liste) alır ve yinelenebilir olanı s'ye birleştirir, s'nin bellek adreslerini değiştirir. Bunlar aynı değil .
W4t3randWind

9

Aradaki fark, birleştirmenin sonuç listeyi düzleştireceği, oysa ekleme işleminin düzeyleri olduğu gibi tutacağıdır:

Örneğin:

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

Append'i kullanarak bir liste listesi elde edersiniz:

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

Bunun yerine birleştirmeyi kullanarak düz bir liste elde edersiniz:

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

5

Buradaki performans testleri doğru değil:

  1. Profili yalnızca bir kez çalıştırmamalısınız.
  2. Ekleme ile + = [] sayısını karşılaştırıyorsanız, append'i yerel bir işlev olarak bildirmeniz gerekir.
  3. zaman sonuçları farklı python sürümlerinde farklıdır: 64 ve 32 bit

Örneğin

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

iyi testler burada bulunabilir: http://markandclick.com/1/post/2012/01/python-list-append-vs.html


yine de, o sayfadaki + = testleri kullanır += [one_var]. Liste oluşturmayı atlarsak, + = en hızlı seçenek olur.
Joe

3

Diğer yanıtlarda açıklanan yönlere ek olarak, bir liste listesi oluşturmaya çalışırken, ekleme ve + [] çok farklı davranışlara sahiptir.

>>> 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'] list1'e ayrı elemanlar olarak '5' ve '6' ekler. list1.append (['5', '6']), ['5', '6'] listesini list1'e tek bir eleman olarak ekler.


2

Diğer yanıtlarda belirtilen yeniden bağlama davranışı belirli durumlarda önemlidir:

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

Bunun nedeni, nesne yerinde değiştirilmiş olsa bile artırılmış atamanın her zaman yeniden bağlanmasıdır. Buradaki yeniden bağlama a[1] = *mutated list*, tuple'lar için çalışmayan olur .


0

önce bir örnek alalım

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

Append () yöntemi, mevcut listeye tek bir öğe ekler

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

Yani burada some_list1 değiştirilecek.

Güncellenmiş:

Listelerin öğelerini (birden fazla öğe) mevcut listedeki uzantıya benzer şekilde birleştirmek için ( Flux tarafından düzeltildiği gibi ) + kullanmak.

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

Yani burada some_list2 ve ["bir şeyler"] birleştirilen iki listedir.


1
Bu yanlış. +=yeni bir liste döndürmez. Programlama SSS der ki: "... listeleri için, __iadd__çağırmak aynıdır extendlistede ve listeyi dönen en neden listeleri için, demek bu. +=Mesajında '' kısaltmasıdır list.extend". Bunu kendiniz için CPython kaynak kodunda da görebilirsiniz: github.com/python/cpython/blob/v3.8.2/Objects/…
Flux

0

"+" Değil listesi mutasyona

.Append () mutasyon eski liste

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.