Whats up with True and False in Python 2

The following is true for the CPython implementation!

Maybe you noticed or already read about it. There is a difference in using
True/False and integer 1/0 for expressing the bool true and false. The expression itself results in the same True and 1 means bool true and False and 0 means bool false. But performance wise True and 1 are different.

Timing True
from timeit import Timer
t = Timer('True')
print t.repeat(3, number=100000000)

Result: [3.35, 3.34, 3.35]

Timing 1
from timeit import Timer
t = Timer('1')
print t.repeat(3, number=100000000)

Result: [1.27, 1.27, 1.28]

As you can see 1 is in average 2.07 seconds faster than True. Ok executing the statement 100000000 times is pretty much, but imagine a high performance while infinity loop, 2 seconds can matter! The question is, why is there a difference.

PyIntObject _Py_ZeroStruct = {
PyObject_HEAD_INIT(&PyBool_Type)
0
};

PyIntObject _Py_TrueStruct = {
PyObject_HEAD_INIT(&PyBool_Type)
1
};

#define Py_False ((PyObject *) &_Py_ZeroStruct)
#define Py_True ((PyObject *) &_Py_TrueStruct)

This is the C code which defines the Python True and False statements. As you can see True and False are int objects with limited features. True is mapped to int value 1 and False to 0.

>>> type(True)
<type 'bool'>
>>> True + True
2

All of this is nice to know, but not the performance issue. The issue is that True and False in Python are globals and not constants. Let me show you the disassembled bytecode of a = True.

0 LOAD_GLOBAL 0 (True)
3 STORE_FAST 0 (a)

And now have a look at a = 1.

0 LOAD_CONST 1 (1)
3 STORE_FAST 0 (a)

In case of the True, Python need to look up the global name True and this takes some time. In fact you can do really bad things in Python 2.x, because of this.

>>> True = 0
>>> False = 1
>>> True
0
>>> False
1

But the good news is, they changed it in Python 3 and a = True now looks like this.

0 LOAD_CONST 1 (True)
3 STORE_FAST 0 (a)

I hope I didn’t miss anything important about this topic. If so, let me know and enlighten me!

UPDATE
A comment suggested I should have a look into the pypy implementation and I did. True and False are globals in pypy, too. But the globals lookup, object creation and everything else is way way faster in pypy. I’m really impressed.

Here are the timing results:

True/False: [0.16, 0.14, 0.14]
1/0: [0.16, 0.14, 0.16]

Thats a big difference and I’m not completely sure, if the test I used for CPython can be applied the same on pypy. I never looked into pypy before, maybe someone can clear things up.