pythontypestype-conversionbooleantruthiness

Are comparisons really allowed to return numbers instead of booleans, and why?


I've found a surprising sentence in the Python documentation under Truth Value Testing:

Operations and built-in functions that have a Boolean result always return 0 or False for false and 1 or True for true, unless otherwise stated.

Relational operators seem to have no excepting statements, so IIUC they could return 0 and 1 instead of False and True on values of some built-in types (e.g. 7 < 3), even nondeterministically.

Thus, in order to satisfy a specification requiring of my code to produce values of type bool or for defensive programming (whenever that's important), should I wrap logical expressions in calls to bool?

Additional question: why does this latitude exist? Does it make things easier somehow for CPython or another implementation?

EDIT The question has been answered and I've accepted, but I'd like to add that in PEP 285 – Adding a bool type I've found the following statements:

  1. All built-in operations that conceptually return a Boolean result will be changed to return False or True instead of 0 or 1; for example, comparisons, the “not” operator, and predicates like isinstance().
  2. All built-in operations that are defined to return a Boolean result will be changed to return False or True instead of 0 or 1. In particular, this affects comparisons (<, <=, ==, !=, >, >=, is, is not, in, not in), the unary operator ‘not’, the built-in functions callable(), hasattr(), isinstance() and issubclass(), the dict method has_key(), the string and unicode methods endswith(), isalnum(), isalpha(), isdigit(), islower(), isspace(), istitle(), isupper(), and startswith(), the unicode methods isdecimal() and isnumeric(), and the ‘closed’ attribute of file objects. The predicates in the operator module are also changed to return a bool, including operator.truth().
  3. The only thing that changes is the preferred values to represent truth values when returned or assigned explicitly. Previously, these preferred truth values were 0 and 1; the PEP changes the preferred values to False and True, and changes built-in operations to return these preferred values.

However, PEPs seem to be less authoritative than the documentation (of which the language and library references are the main parts) and there are numerous deviations from PEPs (many of them mentioned explicitly). So until the team updates it, the stronger guarantees of the PEP aren't to be trusted, I think.

EDIT I've reported it on GH as a Python issue


Solution

  • So, it is probably important to understand that bool objects are int objects, since issubclass(bool, int) is true.

    So isinstance(True, int) and isinstance(False, int) is true.

    Prior to version 2.3 which was released back in 2002, Python lacked a bool type. PEP 285 was the accepted proposal. Prior to this, these operations would return 0 or 1. You can read in "WhatsNew" for 2.3:

    Most of the standard library modules and built-in functions have been changed to return Booleans.

    So, I can only surmise that the language was kept to include 0 and 1 while the standard library etc caught up with this change. But by now, I think everything in built-ins and every part of the standard library I've used will return bool when the return value is meant to be a boolean.

    But keep in mind, from the release notes:

    To sum up True and False in a sentence: they’re alternative ways to spell the integer values 1 and 0, with the single difference that str() and repr() return the strings 'True' and 'False' instead of '1' and '0'.