Rozważ następujące wyrażenia. Zwróć uwagę, że niektóre wyrażenia są powtarzane, aby przedstawić „kontekst”.
(to jest długa lista)
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
Jak poprawnie wydedukować ręcznie wynik takich wyrażeń?
a, *b = 1, 2, 3
rozpakowywaniu. Ale to jest Py3k, prawda?Odpowiedzi:
Przepraszam za długość tego posta, ale zdecydowałem się na kompletność.
Kiedy już znasz kilka podstawowych zasad, nietrudno je uogólnić. Postaram się wyjaśnić na kilku przykładach. Ponieważ mówisz o ocenie tych „ręcznie”, zasugeruję kilka prostych zasad zastępowania. Zasadniczo łatwiejsze może być zrozumienie wyrażenia, jeśli wszystkie iteracje są sformatowane w ten sam sposób.
Tylko w celu rozpakowania, następujące podstawienia są ważne po prawej stronie
=
(tj. Dla wartości r ):Jeśli stwierdzisz, że wartość nie zostanie rozpakowana, cofniesz podstawienie. (Zobacz poniżej, aby uzyskać dalsze wyjaśnienia.)
Gdy zobaczysz „nagie” przecinki, udawaj, że istnieje krotka najwyższego poziomu. Zrób to po lewej i prawej stronie (tj. Dla lvalues i rvalues ):
Mając na uwadze te proste zasady, oto kilka przykładów:
Stosując powyższe zasady, konwertujemy
"XY"
na('X', 'Y')
i zakrywamy puste przecinki w parenach:Korespondencja wizualna sprawia, że dość oczywiste jest, jak działa zadanie.
Oto błędny przykład:
Postępując zgodnie z powyższymi zasadami zastępowania, otrzymujemy:
To jest ewidentnie błędne; zagnieżdżone struktury nie pasują do siebie. Zobaczmy teraz, jak to działa na nieco bardziej złożonym przykładzie:
Stosując powyższe zasady otrzymujemy
Ale teraz jest to jasne ze struktury,
'this'
która nie zostanie rozpakowana, ale przypisana bezpośrednio doc
. Więc cofamy podstawienie.Zobaczmy teraz, co się stanie, gdy zawiniemy
c
krotkę:Staje się
Ponownie błąd jest oczywisty.
c
nie jest już nagą zmienną, ale zmienną wewnątrz sekwencji, więc odpowiednia sekwencja po prawej stronie jest rozpakowywana do(c,)
. Ale sekwencje mają inną długość, więc wystąpił błąd.Teraz do rozszerzonego rozpakowywania za pomocą
*
operatora. Jest to nieco bardziej złożone, ale nadal jest dość proste. Zmienna poprzedzona*
znakiem staje się listą zawierającą elementy z odpowiedniej sekwencji, które nie są przypisane do nazw zmiennych. Zaczynając od dość prostego przykładu:To się stanie
Najprostszym sposobem analizy tego jest praca od końca.
'X'
jest przypisany doa
i'Y'
jest przypisany doc
. Pozostałe wartości w sekwencji są umieszczane na liście i przypisywaneb
.Wartości lvalu lubią
(*a, b)
i(a, *b)
są tylko szczególnymi przypadkami powyższego. Nie możesz mieć dwóch*
operatorów wewnątrz jednej sekwencji lwartości, ponieważ byłoby to niejednoznaczne. Gdzie wartości pójdą w czymś takim(a, *b, *c, d)
- wb
lubc
? Za chwilę rozważę zagnieżdżony przypadek.Tutaj błąd jest dość oczywisty. Element target (
*a
) musi znajdować się w krotce.To działa, ponieważ jest nagi przecinek. Stosowanie zasad ...
Ponieważ nie ma innych zmiennych niż
*a
,*a
wysysa wszystkie wartości w sekwencji rwartości. Co się stanie, jeśli zamienisz(1, 2)
znak na jedną wartość?staje się
Ponownie, błąd tutaj jest oczywisty. Nie możesz rozpakować czegoś, co nie jest sekwencją i
*a
potrzebujesz czegoś do rozpakowania. Więc umieściliśmy to w sekwencjiCo jest równoważne
Wreszcie, jest to powszechny problem:
(1)
to to samo, co1
- potrzebujesz przecinka, aby odróżnić krotkę od instrukcji arytmetycznej.Teraz do zagnieżdżania. Właściwie tego przykładu nie było w Twojej sekcji „NESTED”; może nie zdawałeś sobie sprawy, że jest zagnieżdżony?
Staje się
Pierwsza wartość w krotce najwyższego poziomu zostanie przypisana, a pozostałe wartości w krotce najwyższego poziomu (
2
i3
) zostaną przypisanec
- tak jak powinniśmy się spodziewać.Wyjaśniłem już powyżej, dlaczego pierwsza linia generuje błąd. Druga linia jest głupia, ale oto dlaczego to działa:
Jak wyjaśniono wcześniej, pracujemy od końca.
3
jest przypisanyc
, a następnie pozostałe wartości są przypisane do zmiennej o*
poprzedzających, w tym przypadku(a, b)
. Więc to jest równoważne(a, b) = (1, 2)
, co tak się składa, że działa, ponieważ istnieje odpowiednia liczba elementów. Nie przychodzi mi do głowy żaden powód, dla którego mogłoby to kiedykolwiek pojawić się w działającym kodzie. Podobnie,staje się
Praca od końca,
's'
jest przypisanac
i('t', 'h', 'i')
jest przypisana(a, *b)
. Pracuje ponownie od końca,'t'
jest przypisany doa
i('h', 'i')
jest przypisany do b jako lista. To kolejny głupi przykład, który nigdy nie powinien pojawić się w działającym kodzie.źródło
Uważam, że rozpakowywanie krotki Pythona 2 jest całkiem proste. Każda nazwa po lewej stronie odpowiada całej sekwencji lub pojedynczemu elementowi w sekwencji po prawej stronie. Jeśli nazwy odpowiadają pojedynczym elementom dowolnej sekwencji, musi istnieć wystarczająca liczba nazw, aby objąć wszystkie elementy.
Jednak wydłużone rozpakowywanie może z pewnością być mylące, ponieważ jest tak potężne. W rzeczywistości nigdy nie powinieneś robić ostatnich 10 lub więcej ważnych przykładów, które podałeś - jeśli dane są tak ustrukturyzowane, powinny
dict
instancji klasy lub klasy, a nie w nieustrukturyzowanych formularzach, takich jak listy.Oczywiście nowa składnia może być nadużywana. Odpowiedź na twoje pytanie brzmi: nie powinieneś musieć czytać takich wyrażeń - to zła praktyka i wątpię, czy zostaną użyte.
To, że możesz pisać dowolnie złożone wyrażenia, nie oznacza, że powinieneś. Możesz napisać kod,
map(map, iterable_of_transformations, map(map, iterable_of_transformations, iterable_of_iterables_of_iterables))
ale tego nie zrobisz .źródło
Myślę, że twój kod może wprowadzać w błąd, użyj innej formy, aby to wyrazić.
To tak, jakby używać dodatkowych nawiasów w wyrażeniach, aby uniknąć pytań o pierwszeństwo operatorów. To zawsze dobra inwestycja, aby Twój kod był czytelny.
Wolę używać rozpakowywania tylko do prostych zadań, takich jak zamiana.
źródło