Python trennt die rechte Seite Ausdruck aus der linken Seite-Zuordnung. Zuerst wird die rechte Seite wird ausgewertet und das Ergebnis auf dem Stapel gespeichert wird, und dann die linke Seite Namen verwenden Opcodes zugeordnet, die Werte von der Stapel wieder nehmen.
Für Tupel-Zuordnungen mit 2 oder 3 Elemente, Python verwendet nur den Stapel direkt:
>>> import dis
>>> def foo(a, b):
... a, b = b, a
...
>>> dis.dis(foo)
2 0 LOAD_FAST 1 (b)
3 LOAD_FAST 0 (a)
6 ROT_TWO
7 STORE_FAST 0 (a)
10 STORE_FAST 1 (b)
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
Nach der zwei LOAD_FAST
opcodes (die einen Wert von einer Variablen auf den Stapel schieben), hält die Oberseite des Stapels [a, b]
. Der ROT_TWO
opcode tauscht die obersten zwei Positionen auf dem Stapel, so dass der Stapel jetzt [b, a]
an der Spitze hat. Die beiden STORE_FAST
opcodes nehmen dann diese beiden Werte und speichern sie in den Namen auf der linken Seite der Zuweisung. Die erste STORE_FAST
erscheint einen Wert der oben auf dem Stapel und legt es in a
, wieder am nächsten Pop, den Wert in b
speichern. Die Rotation wird benötigt, da Python garantiert, dass Zuordnungen in einer Zielliste auf der linken Seite von links nach rechts vorgenommen werden.
Für eine 3-Name-Zuweisung wird ROT_THREE
gefolgt von ROT_TWO
ausgeführt, um die obersten drei Elemente auf dem Stapel umzukehren.
Für längere linke seitige Aufgaben wird eine explizite Tupel gebaut:
>>> def bar(a, b, c, d):
... d, c, b, a = a, b, c, d
...
>>> dis.dis(bar)
2 0 LOAD_FAST 0 (a)
3 LOAD_FAST 1 (b)
6 LOAD_FAST 2 (c)
9 LOAD_FAST 3 (d)
12 BUILD_TUPLE 4
15 UNPACK_SEQUENCE 4
18 STORE_FAST 3 (d)
21 STORE_FAST 2 (c)
24 STORE_FAST 1 (b)
27 STORE_FAST 0 (a)
30 LOAD_CONST 0 (None)
33 RETURN_VALUE
Hier wird der Stapel mit [d, c, b, a]
wird verwendet, um ein Tupel zu bauen (in umgekehrter Reihenfolge, BUILD_TUPLE
Pops aus dem Stapel wieder, Schieben das resultierende Tupel auf den Stack), und dann UNPACK_SEQUENCE
das Tupel wieder vom Stapel löscht, schiebt alle Elemente zurück aus dem Tupel zurück auf den Stack für die STORE_FAST
Operationen.
Letztere wie ein verschwenderischer Betrieb zu sein scheint, aber die rechte Seite einer Zuweisung kann etwas ganz anderes, ein Funktionsaufruf sein, dass ein Tupel erzeugt vielleicht, so dass der Python-Interpreter keine Annahmen macht und nutzt die UNPACK_SEQUENCE
Opcode immer. Es tut dies sogar für die zwei- und drei-Namen-Zuweisungsoperationen, but a later (peephole) optimization step ersetzt eine BUILD_TUPLE
/UNPACK_SEQUENCE
Kombination mit 2 oder 3 Argumenten mit den obigen ROT_TWO
und ROT_THREE
Opcodes für die Effizienz.
'Seine Verwendung auf keinen Fall eine temporäre Variable?' Dies eine seltsame Frage. Es klingt, als ob du es weißt. – RedX
Es könnte für Sie interessant sein, die Disassemblierung Ihres Codes mit ['dis'] (http://docs.python.org/3/library/dis.html) anzuzeigen. Spoliers: der Bytecode-Befehl [ 'ROT_TWO'] (http://docs.python.org/2/library/dis.html#opcode-ROT_TWO) verwendet wird. – Kevin
@RedX: Ich hätte diese Frage nicht gestellt, wenn ich es gewusst hätte. Die Verwendung einer temporären Variable ist ein trivialer Ansatz zum Auslagern. – praveen