Neden boş bir listeye (örneğin [] = “”) bir hata atanmıyor?


110

Python 3.4'te yazıyorum

[] = "" 

ve iyi çalışıyor, İstisna ortaya çıkmıyor. Elbette sonrasına []eşit değil "".

[] = ()

ayrıca iyi çalışıyor.

"" = []

yine de beklendiği gibi bir istisna yaratıyor,

() = ""

yine de beklendiği gibi bir istisna yaratır. Yani, ne oluyor?

Yanıtlar:


132

Eşitlik için karşılaştırmıyorsun. Sen atıyorsun .

Python, birden çok hedefe atamanıza izin verir:

foo, bar = 1, 2

atar iki değerleri foove barsırasıyla. İhtiyacınız olan tek şey, sağ tarafta bir dizi veya yinelenebilir ve sol tarafta bir isim listesi veya demetidir .

Ne zaman yaparsan:

[] = ""

Eğer bir atanmış boş isimlerin boş listeye dizisini (boş dizeleri hala dizileri vardır).

Esasen yapmakla aynı şeydir:

[foo, bar, baz] = "abc"

nereye ile bitirmek foo = "a", bar = "b"ve baz = "c"fakat daha az karakter içeren,.

Bununla birlikte, bir dizgeye atama yapamazsınız, bu nedenle ""bir atamanın sol tarafında hiçbir zaman çalışmaz ve her zaman bir sözdizimi hatasıdır.

Atama beyanları belgelerine bakın :

Bir atama ifadesi, ifade listesini değerlendirir (bunun tek bir ifade veya virgülle ayrılmış bir liste olabileceğini, ikincisinin bir demet oluşturduğunu unutmayın) ve sonuçta ortaya çıkan tek nesneyi soldan sağa hedef listelerin her birine atar.

ve

Bir nesnenin, isteğe bağlı olarak parantez veya köşeli parantez içine alınmış bir hedef listeye atanması, aşağıdaki gibi yinelemeli olarak tanımlanır.

Vurgu benim .

Python'un boş liste için bir sözdizimi hatası vermemesi aslında bir hata! Resmi olarak belgelenmiş dilbilgisi boş bir hedef listeye izin vermez ve boş ()için bir hata alırsınız. Bkz hata 23275 ; zararsız bir böcek olarak kabul edilir:

Başlangıç ​​noktası, bunun çok uzun süredir var olduğunun ve zararsız olduğunun farkına varmaktır.

Ayrıca bkz. Neden boş bir listeye atama geçerliyken boş bir demete atama geçerli değil?


36

Dokümantasyondaki Atama ifadeleri bölüm kurallarını takip eder ,

assignment_stmt ::=  (target_list "=")+ (expression_list | yield_expression)

Eğer target listhedeflerin virgülle ayrılmış listesi: orada hedef listesinde hedefler olduğu ve ilgili hedeflere, soldan sağa öğeler, atanır olarak nesne öğeleri aynı sayıda bir iterable olmalıdır.

Nesne, hedef listedeki hedefler ile aynı sayıda öğeye sahip bir dizi olmalıdır ve öğeler soldan sağa karşılık gelen hedeflere atanır.

Öyleyse, dediğinde

[] = ""

"" yinelenebilir (herhangi bir geçerli python dizesi yinelenebilirdir) ve listenin öğeleri üzerinden açılır.

Örneğin,

>>> [a, b, c] = "123"
>>> a, b, c
('1', '2', '3')

Boş bir dizeniz ve boş bir listeniz olduğundan, paketten çıkarılacak hiçbir şey yoktur. Yani hata yok.

Ama bunu dene

>>> [] = "1"
Traceback (most recent call last):
  File "<input>", line 1, in <module>
ValueError: too many values to unpack (expected 0)
>>> [a] = ""
Traceback (most recent call last):
  File "<input>", line 1, in <module>
ValueError: need more than 0 values to unpack

Bu [] = "1"durumda, dizeyi açmaya çalışıyorsunuz"1" boş bir değişkenler listesi üzerinden . Bu nedenle, "paketten çıkarılamayacak kadar çok değerden (0 beklenen)" şikayet ediyor.

Aynı şekilde [a] = "" boş bir dizeniz olması durumunda, gerçekten paketten çıkarılacak bir şey yoktur, ancak onu tek bir değişken üzerinden açarsınız, ki bu yine mümkün değildir. Bu nedenle, "paketini açmak için 0'dan fazla değere ihtiyaç duyduğundan" şikayet ediyor.

Bunun dışında, fark ettiğiniz gibi,

>>> [] = ()

()boş bir demet olduğu için de hata atmaz.

>>> ()
()
>>> type(())
<class 'tuple'>

ve boş bir liste üzerine açıldığında, açılacak hiçbir şey yoktur. Yani hata yok.


Ama ne zaman yaparsan

>>> "" = []
  File "<input>", line 1
SyntaxError: can't assign to literal
>>> "" = ()
  File "<input>", line 1
SyntaxError: can't assign to literal

hata mesajının dediği gibi, bir dize değişmezi atamaya çalışıyorsunuz. Bu mümkün değil. Bu yüzden hataları alıyorsun. Demek gibi

>>> 1 = "one"
  File "<input>", line 1
SyntaxError: can't assign to literal

iç organlar

Dahili olarak, bu atama işlemi UNPACK_SEQUENCEoperasyon koduna çevrilecek ,

>>> dis(compile('[] = ""', "string", "exec"))
  1           0 LOAD_CONST               0 ('')
              3 UNPACK_SEQUENCE          0
              6 LOAD_CONST               1 (None)

Burada, dize boş olduğu için zamanları UNPACK_SEQUENCEkaldırır 0. Ama böyle bir şeye sahip olduğun zaman

>>> dis(compile('[a, b, c] = "123"', "string", "exec"))
  1           0 LOAD_CONST               0 ('123')
              3 UNPACK_SEQUENCE          3
              6 STORE_NAME               0 (a)
              9 STORE_NAME               1 (b)
             12 STORE_NAME               2 (c)
             15 LOAD_CONST               1 (None)
             18 RETURN_VALUE

sıra 123sağdan sola yığına açılır. Yani, yığının tepesi olur 1ve bir sonraki olur 2ve sonuncusu olur 3. Daha sonra sol taraftaki ifadeden değişkenlere yığının tepesinden tek tek atar.


BTW, Python'da, aynı ifadede birden çok atamayı bu şekilde yapabilirsiniz. Örneğin,

a, b, c, d, e, f = u, v, w, x, y, z

bu işe yarar, çünkü sağ el değerleri bir demet oluşturmak için kullanılır ve daha sonra sol taraftaki değerler üzerinden açılır.

>>> dis(compile('a, b, c, d, e, f = u, v, w, x, y, z', "string", "exec"))
  1           0 LOAD_NAME                0 (u)
              3 LOAD_NAME                1 (v)
              6 LOAD_NAME                2 (w)
              9 LOAD_NAME                3 (x)
             12 LOAD_NAME                4 (y)
             15 LOAD_NAME                5 (z)
             18 BUILD_TUPLE              6
             21 UNPACK_SEQUENCE          6
             24 STORE_NAME               6 (a)
             27 STORE_NAME               7 (b)
             30 STORE_NAME               8 (c)
             33 STORE_NAME               9 (d)
             36 STORE_NAME              10 (e)
             39 STORE_NAME              11 (f)
             42 LOAD_CONST               0 (None)
             45 RETURN_VALUE

ancak klasik takas tekniği a, b = b, ayığının en üstündeki öğelerin dönüşünü kullanır. Yalnızca iki veya üç öğeniz varsa, demeti oluşturmak ve paketi açmak yerine özel ROT_TWOve ROT_THREEtalimatlarla işlenirler.

>>> dis(compile('a, b = b, a', "string", "exec"))
  1           0 LOAD_NAME                0 (b)
              3 LOAD_NAME                1 (a)
              6 ROT_TWO
              7 STORE_NAME               1 (a)
             10 STORE_NAME               0 (b)
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE

Ayrıca kullanabilirsiniz dis('[] = ""')uğramadan compile().
Andrea Corbellini

Son örneğinizdeki yöntemi kullanarak üçten fazla değişkeni / öğeyi değiştirirseniz ne olacağını açıklayabilir misiniz?
nanofarad

@hexafraction Sağ taraftaki tüm öğelerle yeni bir demet oluşturacak ve ardından bunları sol taraftaki değişkenler üzerinden açacaktır.
thefourtheye

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.