Ambalajdan çıkarma, genişletilmiş ambalajdan çıkarma ve iç içe yerleştirilmiş uzun süreli ambalajdan çıkarma


105

Aşağıdaki ifadeleri düşünün. Bazı ifadelerin "bağlamı" sunmak için tekrarlandığına dikkat edin.

(bu uzun bir listedir)

a, b = 1, 2                          # simple sequence assignment
a, b = ['green', 'blue']             # list asqignment
a, b = 'XY'                          # string assignment
a, b = range(1,5,2)                  # any iterable will do


                                     # nested sequence assignment

(a,b), c = "XY", "Z"                 # a = 'X', b = 'Y', c = 'Z' 

(a,b), c = "XYZ"                     # ERROR -- too many values to unpack
(a,b), c = "XY"                      # ERROR -- need more than 1 value to unpack

(a,b), c, = [1,2],'this'             # a = '1', b = '2', c = 'this'
(a,b), (c,) = [1,2],'this'           # ERROR -- too many values to unpack


                                     # extended sequence unpacking

a, *b = 1,2,3,4,5                    # a = 1, b = [2,3,4,5]
*a, b = 1,2,3,4,5                    # a = [1,2,3,4], b = 5
a, *b, c = 1,2,3,4,5                 # a = 1, b = [2,3,4], c = 5

a, *b = 'X'                          # a = 'X', b = []
*a, b = 'X'                          # a = [], b = 'X'
a, *b, c = "XY"                      # a = 'X', b = [], c = 'Y'
a, *b, c = "X...Y"                   # a = 'X', b = ['.','.','.'], c = 'Y'

a, b, *c = 1,2,3                     # a = 1, b = 2, c = [3]
a, b, c, *d = 1,2,3                  # a = 1, b = 2, c = 3, d = []

a, *b, c, *d = 1,2,3,4,5             # ERROR -- two starred expressions in assignment

(a,b), c = [1,2],'this'              # a = '1', b = '2', c = 'this'
(a,b), *c = [1,2],'this'             # a = '1', b = '2', c = ['this']

(a,b), c, *d = [1,2],'this'          # a = '1', b = '2', c = 'this', d = []
(a,b), *c, d = [1,2],'this'          # a = '1', b = '2', c = [], d = 'this'

(a,b), (c, *d) = [1,2],'this'        # a = '1', b = '2', c = 't', d = ['h', 'i', 's']

*a = 1                               # ERROR -- target must be in a list or tuple
*a = (1,2)                           # ERROR -- target must be in a list or tuple
*a, = (1,2)                          # a = [1,2]
*a, = 1                              # ERROR -- 'int' object is not iterable
*a, = [1]                            # a = [1]
*a = [1]                             # ERROR -- target must be in a list or tuple
*a, = (1,)                           # a = [1]
*a, = (1)                            # ERROR -- 'int' object is not iterable

*a, b = [1]                          # a = [], b = 1
*a, b = (1,)                         # a = [], b = 1

(a,b),c = 1,2,3                      # ERROR -- too many values to unpack
(a,b), *c = 1,2,3                    # ERROR - 'int' object is not iterable
(a,b), *c = 'XY', 2, 3               # a = 'X', b = 'Y', c = [2,3]


                                     # extended sequence unpacking -- NESTED

(a,b),c = 1,2,3                      # ERROR -- too many values to unpack
*(a,b), c = 1,2,3                    # a = 1, b = 2, c = 3

*(a,b) = 1,2                         # ERROR -- target must be in a list or tuple
*(a,b), = 1,2                        # a = 1, b = 2

*(a,b) = 'XY'                        # ERROR -- target must be in a list or tuple
*(a,b), = 'XY'                       # a = 'X', b = 'Y'

*(a, b) = 'this'                     # ERROR -- target must be in a list or tuple
*(a, b), = 'this'                    # ERROR -- too many values to unpack
*(a, *b), = 'this'                   # a = 't', b = ['h', 'i', 's']

*(a, *b), c = 'this'                 # a = 't', b = ['h', 'i'], c = 's'

*(a,*b), = 1,2,3,3,4,5,6,7           # a = 1, b = [2, 3, 3, 4, 5, 6, 7]

*(a,*b), *c = 1,2,3,3,4,5,6,7        # ERROR -- two starred expressions in assignment
*(a,*b), (*c,) = 1,2,3,3,4,5,6,7     # ERROR -- 'int' object is not iterable
*(a,*b), c = 1,2,3,3,4,5,6,7         # a = 1, b = [2, 3, 3, 4, 5, 6], c = 7
*(a,*b), (*c,) = 1,2,3,4,5,'XY'      # a = 1, b = [2, 3, 4, 5], c = ['X', 'Y']

*(a,*b), c, d = 1,2,3,3,4,5,6,7      # a = 1, b = [2, 3, 3, 4, 5], c = 6, d = 7
*(a,*b), (c, d) = 1,2,3,3,4,5,6,7    # ERROR -- 'int' object is not iterable
*(a,*b), (*c, d) = 1,2,3,3,4,5,6,7   # ERROR -- 'int' object is not iterable
*(a,*b), *(c, d) = 1,2,3,3,4,5,6,7   # ERROR -- two starred expressions in assignment


*(a,b), c = 'XY', 3                  # ERROR -- need more than 1 value to unpack
*(*a,b), c = 'XY', 3                 # a = [], b = 'XY', c = 3
(a,b), c = 'XY', 3                   # a = 'X', b = 'Y', c = 3

*(a,b), c = 'XY', 3, 4               # a = 'XY', b = 3, c = 4
*(*a,b), c = 'XY', 3, 4              # a = ['XY'], b = 3, c = 4
(a,b), c = 'XY', 3, 4                # ERROR -- too many values to unpack

Bu tür ifadelerin sonucunu elle nasıl doğru bir şekilde çıkarabilirim?


28
Dürüst olmak gerekirse, bunların çoğu her gün kodda gördüğünüzden çok daha karmaşık. Listeleri / tupleları açmanın temellerini öğrenin ve iyi olacaksınız.
Rafe Kettler

2
Bunların yinelemeli olduğuna dikkat edin. Yani, ilk birkaçını anlarsanız, her şeyi halledebilirsiniz. Örneğin * (* a, b) 'yi * x ile değiştirmeyi deneyin, hangi x paketlerinin
açıldığını bulun

4
@greengit Gelişmiş Python bilgisine sahip olduğumu düşünüyorum ve sadece genel kuralları biliyorum :) Her köşeyi bilmek zorunda değilsiniz, sadece bazen bir tercümanı çalıştırıp bir şeyi test etmeniz gerekiyor.
Rafe Kettler

Harika bir liste. a, *b = 1, 2, 3Ambalajın nasıl açılacağını gerçekten bilmiyordum . Ama bu Py3k değil mi?
Niklas R

Yanıtlar:


113

Bu yazının uzunluğu için özür dilerim, ancak eksiksizliği tercih etmeye karar verdim.

Birkaç temel kuralı öğrendikten sonra, onları genellemek zor değildir. Birkaç örnekle açıklamak için elimden geleni yapacağım. Bunları "elle" değerlendirmekten bahsettiğiniz için, bazı basit ikame kuralları önereceğim. Temel olarak, tüm yinelemeler aynı şekilde biçimlendirilmişse bir ifadeyi anlamayı daha kolay bulabilirsiniz.

Yalnızca ambalajın açılması amacıyla, aşağıdaki ikameler sağ tarafında geçerlidir =(yani r değerleri için ):

'XY' -> ('X', 'Y')
['X', 'Y'] -> ('X', 'Y')

Bir değerin paketinden çıkarılmadığını fark ederseniz, değiştirmeyi geri alırsınız. (Daha fazla açıklama için aşağıya bakın.)

Ayrıca, "çıplak" virgül gördüğünüzde, üst düzey bir demet varmış gibi düşünün. Bunu hem sol hem de sağ tarafta yapın (yani lvalues ve rvalues ​​için ):

'X', 'Y' -> ('X', 'Y')
a, b -> (a, b)

Bu basit kuralları göz önünde bulundurarak, işte bazı örnekler:

(a,b), c = "XY", "Z"                 # a = 'X', b = 'Y', c = 'Z'

Yukarıdaki kurallarını uygulama, biz dönüştürmek "XY"için ('X', 'Y')Pars çıplak virgül ve kapak:

((a, b), c) = (('X', 'Y'), 'Z')

Buradaki görsel yazışma, ödevin nasıl çalıştığını oldukça açık hale getiriyor.

İşte hatalı bir örnek:

(a,b), c = "XYZ"

Yukarıdaki ikame kurallarının ardından aşağıdakileri elde ederiz:

((a, b), c) = ('X', 'Y', 'Z')

Bu açıkça hatalıdır; iç içe geçmiş yapılar eşleşmiyor. Şimdi biraz daha karmaşık bir örnek için nasıl çalıştığını görelim:

(a,b), c, = [1,2],'this'             # a = '1', b = '2', c = 'this'

Yukarıdaki kuralları uygulayarak,

((a, b), c) = ((1, 2), ('t', 'h', 'i', 's'))

Ancak şimdi 'this', paketten çıkarılmayacak, ancak doğrudanc . Yani ikameyi geri alıyoruz.

((a, b), c) = ((1, 2), 'this')

Şimdi cbir demet içine sardığımızda ne olacağını görelim :

(a,b), (c,) = [1,2],'this'           # ERROR -- too many values to unpack

Olur

((a, b), (c,)) = ((1, 2), ('t', 'h', 'i', 's'))

Yine, hata açıktır. cartık çıplak bir değişken değil, bir dizinin içindeki bir değişkendir ve bu nedenle sağdaki karşılık gelen sıra paketinden çıkarılır (c,). Ancak dizilerin farklı uzunlukları vardır, bu nedenle bir hata vardır.

Şimdi *operatörü kullanarak genişletilmiş ambalajı açmak için . Bu biraz daha karmaşık, ancak yine de oldukça basit. Önündeki değişken *, değişken adlarına atanmamış karşılık gelen diziden herhangi bir öğeyi içeren bir liste haline gelir. Oldukça basit bir örnekle başlayalım:

a, *b, c = "X...Y"                   # a = 'X', b = ['.','.','.'], c = 'Y'

Bu olur

(a, *b, c) = ('X', '.', '.', '.', 'Y')

Bunu analiz etmenin en basit yolu, sonuna kadar çalışmaktır. 'X'atandı ave 'Y'atandıc . Sıradaki kalan değerler bir listeye konur ve atanır b.

Benzer (*a, b)ve (a, *b)yukarıdaki değerlerin sadece özel durumlarıdır. *Bir ldeğer dizisi içinde iki operatörünüz olamaz çünkü bu belirsiz olacaktır. Değerler böyle bir şeyde nereye gider (a, *b, *c, d)- içinde mi byoksa c? İç içe geçmiş durumu birazdan ele alacağım.

*a = 1                               # ERROR -- target must be in a list or tuple

Burada hata oldukça açıklayıcıdır. Hedef ( *a) bir demet içinde olmalıdır.

*a, = (1,2)                          # a = [1,2]

Bu işe yarıyor çünkü çıplak bir virgül var. Kuralların uygulanması ...

(*a,) = (1, 2)

Dışında değişken olmadığından *a, *arvalue dizisindeki tüm değerleri bulandırır. Ya (1, 2)tek bir değerle değiştirirseniz ?

*a, = 1                              # ERROR -- 'int' object is not iterable

olur

(*a,) = 1

Yine, buradaki hata kendi kendini açıklayıcıdır. Sıra olmayan ve *aaçılması gereken bir şeyi paketten çıkaramazsınız . Bu yüzden bir sıraya koyarız

*a, = [1]                            # a = [1]

Eşdeğer olan

(*a,) = (1,)

Son olarak, bu yaygın bir kafa karışıklığı noktasıdır: (1)aynıdır 1- bir demeti aritmetik bir ifadeden ayırmak için virgül kullanmanız gerekir.

*a, = (1)                            # ERROR -- 'int' object is not 

Şimdi yuvalama için. Aslında bu örnek "NESTED" bölümünüzde değildi; belki yuvalanmış olduğunu fark etmediniz?

(a,b), *c = 'XY', 2, 3               # a = 'X', b = 'Y', c = [2,3]

Olur

((a, b), *c) = (('X', 'Y'), 2, 3)

Üst düzey dizideki ilk değer atanır ve üst düzey dizideki ( 2ve 3) kalan değerler atanır c- tam da beklediğimiz gibi.

(a,b),c = 1,2,3                      # ERROR -- too many values to unpack
*(a,b), c = 1,2,3                    # a = 1, b = 2, c = 3

Yukarıda ilk satırın neden bir hata verdiğini zaten açıkladım. İkinci satır aptalca ama işte bu yüzden işe yarıyor:

(*(a, b), c) = (1, 2, 3)

Daha önce açıkladığımız gibi uçtan uca çalışıyoruz. 3atanır cve sonra kalan değerler değişkene atanır *, bu durumda öncekiyle birlikte (a, b). Yani bu (a, b) = (1, 2)işe eşdeğer , çünkü doğru sayıda eleman var. Bunun çalışma kodunda görünmesi için herhangi bir neden düşünemiyorum. Benzer şekilde,

*(a, *b), c = 'this'                 # a = 't', b = ['h', 'i'], c = 's'

olur

(*(a, *b), c) = ('t', 'h', 'i', 's')

Uçlardan çalışmak 's', atanır cve ('t', 'h', 'i')atanır (a, *b). Uçlarından tekrar çalışarak, 't'atanan ave ('h', 'i')bir liste olarak b atanır. Bu, çalışma kodunda asla görünmemesi gereken başka bir aptalca örnek.


24
OP uzun bir liste örnekleri verdiğinden, uzun bir açıklama listesi vermeniz uygun olur.
John Y

7

Python 2 tuple'ı oldukça basit buluyorum. Soldaki her isim ya tam bir diziye ya da sağdaki bir sıradaki tek bir öğeye karşılık gelir. Adlar, herhangi bir sıradaki tek tek öğelere karşılık geliyorsa, tüm öğeleri kapsayacak kadar ad olmalıdır.

Bununla birlikte, uzun süre paketten çıkarma kesinlikle kafa karıştırıcı olabilir çünkü çok güçlüdür. Gerçek şu ki, verdiğiniz son 10 veya daha fazla geçerli örneği asla yapmamalısınız - eğer veri yapılandırılmışsa, dictlisteler gibi yapılandırılmamış formlarda değil, bir veya sınıf örneğinde olmalıdır .

Açıkça, yeni sözdizimi kötüye kullanılabilir. Sorunuzun cevabı, bunun gibi ifadeleri okumak zorunda olmamanız gerektiğidir - bunlar kötü bir uygulamadır ve kullanılacağından şüpheliyim.

Sırf gelişigüzel karmaşık ifadeler yazabilmeniz, yazmanız gerektiği anlamına gelmez. Gibi kod yazabilirsin map(map, iterable_of_transformations, map(map, iterable_of_transformations, iterable_of_iterables_of_iterables))ama yapmazsın .


Not: Birkaç seviye daha karmaşık dışında, bu şekilde kod yazdım. Sadece bir alıştırma olarak tasarlanmıştı ve üç ay sonra bunun benim için anlamsız olacağı ve başka hiç kimse için asla anlaşılmaz olmayacağı konusunda tam bir bilgi ile yapıldı . Doğru hatırlıyorsam, noktayı çokgen testinde uyguladı, bazı koordinat dönüşümleri yaptı ve bazı SVG'ler, HTML ve JavaScript oluşturdu.
agf

3

Kodunuzun yanıltıcı olabileceğini düşünüyorum, onu ifade etmek için başka bir form kullanın.

Operatörlerin önceliği ile ilgili soruları önlemek için ifadelerde fazladan parantez kullanmak gibidir. Kodunuzu okunabilir hale getirmek için her zaman iyi bir yatırımım.

Paket açmayı yalnızca değiştirme gibi basit görevler için kullanmayı tercih ederim.

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.