Why is if True
slower than if 1
in Python? Shouldn't if True
be faster than if 1
?
I was trying to learn the timeit
module. Starting with the basics, I tried these:
>>> 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
I am confused by these things:
bool
first and then checked. So why is if True
slower than if 1
?test3
slower than test1
even though only the return
values are different?test4
a little faster than test2
?NOTE: I ran timeit
three times and took the average of the results, then posted the times here along with the code.
This question does not relate to how to do micro benchmarking(which I did in this example but I also understand that it is too basic) but why checking a 'True' variable is slower than a constant.
Note that a vector of bools is a special type of vector. And, yes, using that will definitely impact speed. Bool is smaller and hence can be faster if you are keeping large arrays of bools/ints, in terms of cache efficiency.
You can check if a value is either truthy or falsy with the built-in bool() function. According to the Python Documentation, this function: Returns a Boolean value, i.e. one of True or False .
If you want to check that a variable is explicitly True or False (and is not truthy/falsy), use is ( if variable is True ). If you want to check if a variable is equal to 0 or if a list is empty, use if variable == 0 or if variable == [] .
We can evaluate values and variables using the Python bool() function. This method is used to return or convert a value to a Boolean value i.e., True or False, using the standard truth testing procedure.
True
and False
are not keywords in Python 2.
They must resolve at runtime. This has been changed in Python 3
Same test on 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
Time error is in 1%, which is acceptable.
Bytecode disassembly makes difference obvious.
>>> 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
As Kabie mentioned, True
and False
are globals in Python 2. Lots of stuff is going on to access them.
>>> dis.dis(test2) 3 0 LOAD_CONST 1 (1) 3 RETURN_VALUE
Python compiler was able to recognize 1
as a constantly "truthy" expression and optimize redundant condition away!
>>> 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
Pretty much the same as test1
, with one more LOAD_GLOBAL
.
>>> dis.dis(test4) 3 0 LOAD_GLOBAL 0 (True) 3 RETURN_VALUE
See test2
. But LOAD_GLOBAL
is a bit more costly than LOAD_CONST
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With