real - python types
¿Cómo funciona internamente el intercambio de miembros en las tuplas de python(a, b)=(b, a)? (1)
Python separa la expresión del lado derecho de la asignación del lado izquierdo. Primero se evalúa el lado derecho, y el resultado se almacena en la pila, y luego los nombres del lado izquierdo se asignan usando códigos de operación que toman valores de la pila nuevamente.
Para las asignaciones de tuplas con 2 o 3 elementos, Python solo usa la pila directamente:
>>> 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
Después de los dos LOAD_FAST
(que empujan un valor de una variable a la pila), la parte superior de la pila contiene [a, b]
. El ROT_TWO intercambia las dos posiciones superiores en la pila, por lo que ahora la pila tiene [b, a]
en la parte superior. Los dos STORE_FAST
toman esos dos valores y los almacenan en los nombres en el lado izquierdo de la asignación. El primer STORE_FAST
un valor de la parte superior de la pila y lo coloca en a
, el siguiente aparece nuevamente, almacenando el valor en b
. La rotación es necesaria porque Python garantiza que las asignaciones en una lista de objetivos en el lado izquierdo se realicen de izquierda a derecha.
Para una asignación de 3 nombres, se ROT_THREE
seguido de ROT_TWO
para revertir los tres elementos principales de la pila.
Para las asignaciones más largas del lado izquierdo, se construye una tupla explícita:
>>> 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
Aquí la pila con [d, c, b, a]
se usa para construir una tupla (en orden inverso, BUILD_TUPLE
de la pila, empujando la tupla resultante sobre la pila), y luego UNPACK_SEQUENCE
saca la tupla de la pila de nuevo , vuelve a STORE_FAST
todos los elementos de la tupla en la pila para las operaciones STORE_FAST
.
El último puede parecer una operación inútil, pero el lado derecho de una asignación puede ser algo completamente diferente, una llamada de función que quizás produzca una tupla, por lo que el intérprete de Python no hace suposiciones y usa siempre el código UNPACK_SEQUENCE
. Lo hace incluso para las operaciones de asignación de dos y tres nombres, pero un paso de optimización posterior (peephole) reemplaza una combinación BUILD_TUPLE
/ UNPACK_SEQUENCE
con 2 o 3 argumentos con los opcodes ROT_TWO
y ROT_THREE
para mayor eficiencia.
In [55]: a = 5
In [56]: b = 6
In [57]: (a, b) = (b, a)
In [58]: a
Out[58]: 6
In [59]: b
Out[59]: 5
¿Cómo funciona este intercambio de valores de ayb internamente? Definitivamente no está utilizando una variable temporal.