2010-02-16 4 views
9

Listenin amaçlanan davranışıyla ilgili bir şey eksik olabilir, ancak neden aşağıdakiler oluyor?Python'da listelerin bir listesini genişletiyor musunuz?

x = [[],[]] 
y = [[]] * 2 

print x  # [[],[]] 
print y  # [[],[]] 
print x == y # True 

x[0].extend([1]) 
y[0].extend([1]) 

print x # [[1],[]], which is what I'd expect 
print y # [[1],[1]], wtf? 

Ben tam olarak emin değilim gerçi, * operatör burada beklenmedik bir şey yaptığını tahmin ediyorum. Kaputun altında, orijinal x ve y (uzatmadan önce) yapmak, == ve repr'un her ikisi de aynı oldukları gibi görünmesine rağmen aslında eşit olmayacak gibi görünüyor.

Sadece bunun için geldim çünkü çalışma zamanında belirlenen bir boyuttaki boş listelerin bir listesini önceden doldurmak istedim ve daha sonra hayal ettiğim şekilde çalışmadığını fark ettim. Aynı şeyi yapmak için daha iyi bir yol bulabilirim, ama şimdi bunun neden işe yaramadığını merak ediyorum. Bu Python 2.5.2 BTW - Ben daha yeni bir sürümü yüklü değil bu yüzden eğer bu bir hata ise zaten düzeltildi emin değilim.

+0

Eklemenin ne olduğunun farkındayım, sadece soru uğruna tartışılmış bir örnekle geliyordum. –

cevap

16

[something] * 2 söz konusu olduğunda, python sadece bir referans kopyası yapmaktadır. Bu nedenle, kapalı tür (ler) değişebilir ise, bunların değiştirilmesi, öğenin başvurulan herhangi bir yere yansıtılacaktır.

Örneğinizde, y[0] ve y[1], aynı kapalı liste nesnesine işaret eder. Bunu y[0] is y[1] veya dönüşümlü olarak id(y[0]) == id(y[1]) yaparak doğrulayabilirsiniz.

Bununla birlikte yeniden atama olabilir liste elemanlarını, sen yapmış olsaydı bu yüzden:

y[0] = [1] 

Sen ediyorum elemanı "1" içeren yeni bir listeye ilk öğesini yeniden bağlanmış ve giderdi beklenen sonucunu aldın.

Python deposundaki konteynerler, başvuruları depolar ve çoğu öğede aynı öğeye birden çok kez başvuruda bulunmak mümkündür. Bunun bir yararı sınırlı olmasına rağmen, bir liste kendisini bir unsur olarak tanımlayabilir. Eğer değişmez türlerini içeren bir liste çarpılır olsaydı

Bu sorun ortaya olmazdı:

a = [0, 1] * 2 

yukarıda sana listeyi [0, 1, 0, 1] ve aynı nesneye 1 noktasının aslında iki örneği, verecekti ama değişmez olduklarından, "1" içeren int nesnesinin değerini değiştiremezsiniz, yalnızca öğeleri yeniden atayabilirsiniz.

Yapıyor: a[1] = 5, [0, 5, 0, 1] olarak gösterilen a sonuçlanır.

+0

Teşekkürler, bu mantıklı. –

4

y = [[]] * 2 ifadesi, y numaralı belgeyi aynı listeden 2 kopya içeren bir listeye bağlar. Kullanın:

y = [[], []] 

veya

y = [[] for n in range(2)] 
+4

Teknik olarak, aynı listeye iki kopya göndermiyor, kopyalar değil. – Crast

+0

Yani "2 kopya" yerine "2 referans", değil mi?Ben bir düzenleme olarak önerdi – kmonsoor

1

y tek bir değişken, listeye iki başvuru içerir.