Betrachten Sie die folgenden Ausdrücke. Beachten Sie, dass einige Ausdrücke wiederholt werden, um den "Kontext" darzustellen.
(Dies ist eine lange Liste)
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
Wie kann man das Ergebnis solcher Ausdrücke von Hand richtig ableiten?
python
python-3.x
iterable-unpacking
argument-unpacking
Baumkodierer
quelle
quelle
a, *b = 1, 2, 3
Art des Auspackens. Aber das ist Py3k, oder?Antworten:
Ich entschuldige mich für die Länge dieses Beitrags, aber ich habe mich für die Vollständigkeit entschieden.
Sobald Sie einige Grundregeln kennen, ist es nicht schwer, sie zu verallgemeinern. Ich werde mein Bestes geben, um dies anhand einiger Beispiele zu erklären. Da Sie über die Bewertung dieser "von Hand" sprechen, schlage ich einige einfache Substitutionsregeln vor. Grundsätzlich fällt es Ihnen möglicherweise leichter, einen Ausdruck zu verstehen, wenn alle iterablen Elemente auf dieselbe Weise formatiert sind.
Nur zum Auspacken gelten die folgenden Ersetzungen auf der rechten Seite von
=
(dh für rWerte ):Wenn Sie feststellen, dass ein Wert nicht entpackt wird, machen Sie die Ersetzung rückgängig. (Weitere Erklärungen finden Sie weiter unten.)
Wenn Sie "nackte" Kommas sehen, tun Sie so, als gäbe es ein Tupel der obersten Ebene. Tun Sie dies sowohl auf der linken als auch auf der rechten Seite (dh für lWerte und rWerte ):
In Anbetracht dieser einfachen Regeln sind hier einige Beispiele:
Unter Anwendung der oben genannten Regeln wandeln wir
"XY"
auf('X', 'Y')
, und decken die nackten Kommas in Pars:Die visuelle Entsprechung hier macht ziemlich deutlich, wie die Zuordnung funktioniert.
Hier ist ein fehlerhaftes Beispiel:
Nach den oben genannten Substitutionsregeln erhalten wir Folgendes:
Dies ist eindeutig falsch; Die verschachtelten Strukturen stimmen nicht überein. Nun wollen wir sehen, wie es für ein etwas komplexeres Beispiel funktioniert:
Unter Anwendung der oben genannten Regeln erhalten wir
Aber jetzt geht aus der Struktur hervor, dass
'this'
sie nicht entpackt, sondern direkt zugewiesen wirdc
. Also machen wir die Substitution rückgängig.Nun wollen wir sehen, was passiert, wenn wir
c
ein Tupel einpacken:Wird
Auch hier ist der Fehler offensichtlich.
c
ist keine nackte Variable mehr, sondern eine Variable innerhalb einer Sequenz, und so wird die entsprechende Sequenz rechts entpackt(c,)
. Die Sequenzen haben jedoch eine andere Länge, sodass ein Fehler auftritt.Jetzt zum erweiterten Auspacken mit dem
*
Bediener. Das ist etwas komplexer, aber immer noch ziemlich einfach. Eine vorangestellte Variable wird*
zu einer Liste, die Elemente aus der entsprechenden Sequenz enthält, die nicht den Variablennamen zugewiesen sind. Beginnen wir mit einem ziemlich einfachen Beispiel:Das wird
Der einfachste Weg, dies zu analysieren, besteht darin, von den Enden aus zu arbeiten.
'X'
ist zugeordneta
und'Y'
ist zugeordnetc
. Die restlichen Werte in der Sequenz werden in eine Liste aufgenommen und zugewiesenb
.L-Werte mögen
(*a, b)
und(a, *b)
sind nur Sonderfälle der oben genannten. Sie können nicht zwei*
Operatoren in einer lvalue-Sequenz haben, da dies nicht eindeutig wäre. Wohin würden die Werte in so etwas gehen(a, *b, *c, d)
- inb
oderc
? Ich werde gleich auf den verschachtelten Fall eingehen.Hier ist der Fehler ziemlich selbsterklärend. Das Ziel (
*a
) muss sich in einem Tupel befinden.Dies funktioniert, weil es ein nacktes Komma gibt. Regeln anwenden ...
Da es keine anderen Variablen als gibt
*a
,*a
werden alle Werte in der rvalue-Sequenz verschluckt. Was ist, wenn Sie das(1, 2)
durch einen einzelnen Wert ersetzen ?wird
Auch hier ist der Fehler selbsterklärend. Sie können etwas nicht auspacken, das keine Sequenz ist und
*a
zum Auspacken etwas benötigt. Also setzen wir es in eine ReihenfolgeWelches ist äquivalent zu
Schließlich ist dies ein häufiger Punkt der Verwirrung: Es
(1)
ist dasselbe wie1
- Sie benötigen ein Komma, um ein Tupel von einer arithmetischen Aussage zu unterscheiden.Nun zum Verschachteln. Eigentlich war dieses Beispiel nicht in Ihrem Abschnitt "NESTED"; Vielleicht haben Sie nicht bemerkt, dass es verschachtelt ist?
Wird
Der erste Wert im Tupel der obersten Ebene wird zugewiesen, und die verbleibenden Werte im Tupel der obersten Ebene (
2
und3
) werden zugewiesenc
- genau wie wir es erwarten sollten.Ich habe oben bereits erklärt, warum die erste Zeile einen Fehler auslöst. Die zweite Zeile ist albern, aber hier ist, warum es funktioniert:
Wie bereits erläutert, arbeiten wir von Anfang an.
3
wird zugewiesenc
, und dann werden die verbleibenden Werte der Variablen mit der*
vorhergehenden zugewiesen , in diesem Fall(a, b)
. Das entspricht also(a, b) = (1, 2)
, was zufällig funktioniert, weil es die richtige Anzahl von Elementen gibt. Ich kann mir keinen Grund vorstellen, warum dies jemals im Arbeitscode erscheinen würde. Ähnlich,wird
Arbeiten von den Enden,
's'
ist zugeordnetc
und('t', 'h', 'i')
zugeordnet(a, *b)
. Von den Enden aus wieder arbeiten,'t'
wird zugewiesena
und('h', 'i')
wird b als Liste zugewiesen. Dies ist ein weiteres dummes Beispiel, das niemals im Arbeitscode erscheinen sollte.quelle
Ich finde das Auspacken des Python 2-Tupels ziemlich einfach. Jeder Name links entspricht entweder einer ganzen Sequenz oder einem einzelnen Element in einer Sequenz rechts. Wenn Namen einzelnen Elementen einer beliebigen Sequenz entsprechen, müssen genügend Namen vorhanden sein, um alle Elemente abzudecken.
Ein längeres Auspacken kann jedoch sicherlich verwirrend sein, da es so leistungsstark ist. Die Realität ist, dass Sie niemals die letzten 10 oder mehr gültigen Beispiele machen sollten, die Sie angegeben haben. Wenn die Daten so strukturiert sind, sollten sie sich in einer
dict
oder einer Klasseninstanz befinden und nicht in unstrukturierten Formen wie Listen.Natürlich kann die neue Syntax missbraucht werden. Die Antwort auf Ihre Frage lautet, dass Sie solche Ausdrücke nicht lesen müssen - sie sind eine schlechte Praxis, und ich bezweifle, dass sie verwendet werden.
Nur weil Sie beliebig komplexe Ausdrücke schreiben können, heißt das nicht, dass Sie es sollten. Sie könnten Code wie schreiben,
map(map, iterable_of_transformations, map(map, iterable_of_transformations, iterable_of_iterables_of_iterables))
aber Sie tun es nicht .quelle
Ich denke, Ihr Code kann irreführend sein. Verwenden Sie ein anderes Formular, um ihn auszudrücken.
Es ist so, als würden Sie zusätzliche Klammern in Ausdrücken verwenden, um Fragen zur Priorität von Operatoren zu vermeiden. Es ist immer eine gute Investition, Ihren Code lesbar zu machen.
Ich bevorzuge das Auspacken nur für einfache Aufgaben wie das Tauschen.
quelle