Intrigado por esta pregunta sobre bucles infinitos en perl: while (1) Vs. para (;;) ¿Hay una diferencia de velocidad? , Decidí ejecutar una comparación similar en Python. Esperaba que el compilador generara el mismo código de bytes para while(True): pass
y while(1): pass
, pero este no es el caso en python2.7.
El siguiente guión:
import dis
def while_one():
while 1:
pass
def while_true():
while True:
pass
print("while 1")
print("----------------------------")
dis.dis(while_one)
print("while True")
print("----------------------------")
dis.dis(while_true)
produce los siguientes resultados:
while 1
----------------------------
4 0 SETUP_LOOP 3 (to 6)
5 >> 3 JUMP_ABSOLUTE 3
>> 6 LOAD_CONST 0 (None)
9 RETURN_VALUE
while True
----------------------------
8 0 SETUP_LOOP 12 (to 15)
>> 3 LOAD_GLOBAL 0 (True)
6 JUMP_IF_FALSE 4 (to 13)
9 POP_TOP
9 10 JUMP_ABSOLUTE 3
>> 13 POP_TOP
14 POP_BLOCK
>> 15 LOAD_CONST 0 (None)
18 RETURN_VALUE
Usar while True
es notablemente más complicado. ¿Por qué es esto?
En otros contextos, Python actúa como si fuera True
igual a 1:
>>> True == 1
True
>>> True + True
2
¿Por qué while
distingue a los dos?
Noté que python3 evalúa las declaraciones utilizando operaciones idénticas:
while 1
----------------------------
4 0 SETUP_LOOP 3 (to 6)
5 >> 3 JUMP_ABSOLUTE 3
>> 6 LOAD_CONST 0 (None)
9 RETURN_VALUE
while True
----------------------------
8 0 SETUP_LOOP 3 (to 6)
9 >> 3 JUMP_ABSOLUTE 3
>> 6 LOAD_CONST 0 (None)
9 RETURN_VALUE
¿Hay un cambio en python3 en la forma en que se evalúan los booleanos?
Respuestas:
En Python 2.x,
True
no es una palabra clave, sino solo una constante global incorporada que se define como 1 en elbool
tipo. Por lo tanto, el intérprete todavía tiene que cargar el contenido deTrue
. En otras palabras,True
es reasignable:En Python 3.x realmente se convierte en una palabra clave y una constante real:
así, el intérprete puede reemplazar el
while True:
bucle con un bucle infinito.fuente
while 1
ywhile True
son idénticos en Python 3?Esto no está del todo bien
ya que uno todavía puede salir del bucle. Pero es cierto que
else
nunca se accedería a dicha cláusula de bucle en Python 3. Y también es cierto que simplificar la búsqueda de valores hace que se ejecute tan rápido comowhile 1
en Python 2.Comparación de rendimiento
Demostrando la diferencia en el tiempo para un bucle while algo no trivial:
Preparar
Python 2
Python 3
Explicación
Para explicar la diferencia, en Python 2:
pero en Python 3:
Dado que
True
es una palabra clave en Python 3, el intérprete no tiene que buscar el valor para ver si alguien lo reemplazó con algún otro valor. Pero como se puede asignarTrue
a otro valor, el intérprete tiene que buscarlo cada vez.Conclusión para Python 2
Si tiene un bucle estrecho y de larga duración en Python 2, probablemente debería usar en
while 1:
lugar dewhile True:
.Conclusión para Python 3
Úselo
while True:
si no tiene ninguna condición para salir de su bucle.fuente
Esta es una pregunta de 7 años que ya tiene una gran respuesta, pero un concepto erróneo en la pregunta, que no se aborda en ninguna de las respuestas, hace que sea potencialmente confuso para algunas de las otras preguntas marcadas como duplicadas.
De hecho,
while
no está haciendo nada diferente aquí. Se distingue1
yTrue
exactamente de la misma manera que lo hace el+
ejemplo.Aquí está 2.7:
Ahora compare:
Emite un
LOAD_GLOBAL (True)
para cada unoTrue
, y el optimizador no puede hacer nada con un global. Entonces, sewhile
distingue1
yTrue
exactamente por la misma razón que lo+
hace. (Y==
no los distingue porque el optimizador no optimiza las comparaciones).Ahora compare 3.6:
Aquí, emite una
LOAD_CONST (True)
para la palabra clave, que el optimizador puede aprovechar. Entonces,True + 1
no distingue, exactamente por la misma razónwhile True
que no lo hace. (Y==
todavía no los distingue porque el optimizador no optimiza las comparaciones).Mientras tanto, si el código no está optimizado a cabo, el intérprete termina el tratamiento
True
y1
exactamente el mismo en los tres de estos casos.bool
es una subclase deint
, hereda la mayoría de sus métodosint
yTrue
tiene un valor entero interno de 1. Entonces, ya sea que esté haciendo unawhile
prueba (__bool__
en 3.x,__nonzero__
en 2.x), una comparación (__eq__
) o aritmética (__add__
), está llamando al mismo método ya sea que useTrue
o1
.fuente