Why Is Bool a Subclass of Int

Why is bool a subclass of int?

From a comment on http://www.peterbe.com/plog/bool-is-int

It is perfectly logical, if you were around when the bool type was
added to python (sometime around 2.2 or 2.3).

Prior to introduction of an actual bool type, 0 and 1 were the
official representation for truth value, similar to C89. To avoid
unnecessarily breaking non-ideal but working code, the new bool type
needed to work just like 0 and 1. This goes beyond merely truth value,
but all integral operations. No one would recommend using a boolean
result in a numeric context, nor would most people recommend testing
equality to determine truth value, no one wanted to find out the hard
way just how much existing code is that way. Thus the decision to make
True and False masquerade as 1 and 0, respectively. This is merely a
historical artifact of the linguistic evolution.

Credit goes to dman13 for this nice explanation.

Why is my boolean value an instance of int?

That's because bool is a subclass of int.

Quoting from the Python Data Model:

Booleans (bool)

These represent the truth values False and True. The two objects representing the values False and True are the only Boolean objects. The Boolean type is a subtype of the integer type, and Boolean values behave like the values 0 and 1, respectively, in almost all contexts, the exception being that when converted to a string, the strings "False" or "True" are returned, respectively.

Answer to comment:

Would it also return True if you did isinstance(bool, int)?

No. True and False are instances of bool and therefore instances of the parent class int, but bool itself is not an instance of int. Being a class it's an instance of type and a subclass of int.

>>> isinstance(bool, int)
False
>>> isinstance(bool, type)
True
>>> issubclass(bool, int)
True

Why are booleans considered integers?

It is in the documentation: Numeric Types

There are three distinct numeric types: integers, floating point numbers, and complex numbers. In addition, Booleans are a subtype of integers.

True and False are numerically equal to 1 and 0 in Python, respectively.

Because bool is a subclass of int, as established above, isinstance returns true, as documented:

isinstance(object, classinfo)

Return True if the object argument is an instance of the classinfo argument, or of a subclass thereof.

Why does bool exist when we can use int?

Why does bool exist when we can use int?

Well, you don't need something as large as an int to represent two states so it makes sense to allow for a smaller type to save space

Why not we use an integer that can return only two possible values, Such as 1 or 0.

That is exactly what bool is. It is an unsigned integer type that represents true (1) or false (0).


Another nice thing about having a specific type for this is that it express intent without any need for documentation. If we had a function like (warning, very contrived example)

void output(T const & val, bool log)

It is easy to see that log is an option and if we pass false it wont log. If it were instead

void output(T const & val, int log)

Then we aren't sure what it does. Is it asking for a log level? A flag on whether to log or not? Something else?

Comparing boolean and int using isinstance

For historic reasons, bool is a subclass of int, so True is an instance of int. (Originally, Python had no bool type, and things that returned truth values returned 1 or 0. When they added bool, True and False had to be drop-in replacements for 1 and 0 as much as possible for backward compatibility, hence the subclassing.)

The correct way to "solve" this depends on exactly what you consider the problem to be.

  • If you want True to stop being an int, well, too bad. That's not going to happen.
  • If you want to detect booleans and handle them differently from other ints, you can do that:

    if isinstance(whatever, bool):
    # special handling
    elif isinstance(whatever, (float, int)):
    # other handling
  • If you want to detect objects whose specific class is exactly float or int, rejecting subclasses, you can do that:

    if type(whatever) in (float, int):
    # Do stuff.
  • If you want to detect all floats and ints, you're already doing that.

Why bool and int are not considered as a type error when str and float is required?

bool is a subclass of int, which means they are both natural numbers. Natural numbers are a subset of real numbers, so they are acceptable where a float is acceptable.

That int is acceptable where float is specified is explicitly called out in PEP 484 -- Type Hints:

Rather than requiring that users write import numbers and then use numbers.Float etc., this PEP proposes a straightforward shortcut that is almost as effective: when an argument is annotated as having type float, an argument of type int is acceptable[.]

  • The str component in your Union[] doesn't play any role here; you could remove it and still the assignment would be accepted. It's purely the float type annotation that makes 12 and False acceptable values.

  • The int() call is entirely redundant, the 12 literal syntax already produces an int object.

python numbers.Number with boolean

Early Python (before 2.2?) didn't have a separate boolean type: people used 0 and 1 instead. When the bool type was added, it was made a subclass of ints to simplify the use of existing code in new Pythons.



Related Topics



Leave a reply



Submit