python - soporta - ¿Por qué es más lento si es verdadero si 1?
optimizar consultas mysql explain (2)
¿Por qué es if True
más lento que if 1
en Python? ¿No debería if True
más rápido que if 1
?
Estaba tratando de aprender el módulo timeit
. A partir de lo básico, probé estos:
>>> def test1():
... if True:
... return 1
... else:
... return 0
>>> print timeit("test1()", setup = "from __main__ import test1")
0.193144083023
>>> def test2():
... if 1:
... return 1
... else:
... return 0
>>> print timeit("test2()", setup = "from __main__ import test2")
0.162086009979
>>> def test3():
... if True:
... return True
... else:
... return False
>>> print timeit("test3()", setup = "from __main__ import test3")
0.214574098587
>>> def test4():
... if 1:
... return True
... else:
... return False
>>> print timeit("test4()", setup = "from __main__ import test4")
0.160849094391
Estoy confundido por estas cosas:
- De acuerdo con la respuesta del Sr. Sylvain Defresne en esta pregunta , todo se convierte implícitamente en un
bool
primero y luego se comprueba. Entonces, ¿por qué esif True
más lento queif 1
? - ¿Por qué es
test3
más lento quetest1
aunque solo los valores dereturn
son diferentes? - Me gusta la pregunta 2, pero ¿por qué es
test4
un poco más rápido quetest2
?
NOTA: Lo timeit
tres veces y tomé el promedio de los resultados, luego publiqué los tiempos aquí junto con el código.
Esta pregunta no se relaciona con la forma de realizar un micro benchmarking (lo que hice en este ejemplo, pero también entiendo que es demasiado básico), pero la razón por la que verificar una variable "Verdadera" es más lenta que una constante.
Desmontaje bytecode hace la diferencia obvia.
>>> dis.dis(test1)
2 0 LOAD_GLOBAL 0 (True)
3 JUMP_IF_FALSE 5 (to 11)
6 POP_TOP
3 7 LOAD_CONST 1 (1)
10 RETURN_VALUE
>> 11 POP_TOP
5 12 LOAD_CONST 2 (0)
15 RETURN_VALUE
16 LOAD_CONST 0 (None)
19 RETURN_VALUE
Como mencionó Kabie, True
y False
son globales en Python 2. Muchas cosas van a tener acceso a ellos.
>>> dis.dis(test2)
3 0 LOAD_CONST 1 (1)
3 RETURN_VALUE
El compilador de Python pudo reconocer 1
como una expresión "veraz" constante y optimizar la condición redundante.
>>> dis.dis(test3)
2 0 LOAD_GLOBAL 0 (True)
3 JUMP_IF_FALSE 5 (to 11)
6 POP_TOP
3 7 LOAD_GLOBAL 0 (True)
10 RETURN_VALUE
>> 11 POP_TOP
5 12 LOAD_GLOBAL 1 (False)
15 RETURN_VALUE
16 LOAD_CONST 0 (None)
19 RETURN_VALUE
Más o menos lo mismo que test1
, con un LOAD_GLOBAL
más.
>>> dis.dis(test4)
3 0 LOAD_GLOBAL 0 (True)
3 RETURN_VALUE
Ver test2
. Pero LOAD_GLOBAL
es un poco más costoso que LOAD_CONST
.
True
y False
no son palabras clave en Python 2 .
Deben resolverse en tiempo de ejecución. Esto ha sido cambiado en Python 3.
La misma prueba en Python 3:
>>> timeit.timeit(''test1()'',setup="from __main__ import test1", number=10000000)
2.806439919999889
>>> timeit.timeit(''test2()'',setup="from __main__ import test2", number=10000000)
2.801301520000038
>>> timeit.timeit(''test3()'',setup="from __main__ import test3", number=10000000)
2.7952816800000164
>>> timeit.timeit(''test4()'',setup="from __main__ import test4", number=10000000)
2.7862537199999906
El error de tiempo es del 1%, lo cual es aceptable.