What the differences are between Python bools and ints

July 9, 2014

I mentioned in the previous entry that Python's bool class is actually a subclass of int (and the bool docstring will tell you this if you bother to read it with help() before, say, diving into the CPython source code like a system programmer). Since I was just looking at this, I might as well write down the low-level differences between ints and bools. Bools have:

  • a custom __repr__ that reports True or False instead of the numeric value; this is also used as the custom __str__ for bool.

    (The code is careful to intern these strings so that no matter how many times you repr() or str() a boolean, only one copy of the literal 'True' or 'False' string will exist.)

  • a __new__ that returns either the global True object or the global False object depending on the truth value of what it's given.

  • custom functions for &, |, and ^ that implement boolean algebra instead of the standard bitwise operations if both arguments are either True or False. Note that eg 'True & 1' results in a bitwise operation and an int object, even though 1 is strongly equal to True.

That's it.

I'm not quite sure how bool blocks being subclassed and I'm not curious enough right now to work it out.
Update: see the comments for the explanation.

The global True and False objects are of course distinct from what is in effect the global 0 and 1 objects that are all but certain to exist. This means that their id() is different (at least in CPython), since the id() is the memory address of their C-level object struct.

(In modern versions of both CPython 2 and CPython 3 it turns out that global 0 and 1 objects are guaranteed to exist, because 'small integers' between -5 and 257 are actually preallocated as the interpreter is initializing itself.)

Comments on this page:

It blocks being subclassed by adding a special check in the CPython type object which in turn inspects a "this is an OK base type" flag set by most built-in types but not by bool.

You can do the same yourself either by using the C API to clear the Py_TPFLAGS_BASETYPE bit on a regular type, or by adding a metaclass that inspects the __bases__ property of new classes and raises an exception if the new "final" class is in it.

Written on 09 July 2014.
« Exploring a surprise with equality in Python
The core security problem of SSL on the web is too much trust »

Page tools: View Source, View Normal, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Wed Jul 9 00:27:09 2014
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.