3

Since the introduction of bool, it has been a subclass of int, and bools can be “cast” into integers implicitly:

>>> issubclass(bool, int)
True
>>> ['one', 'two'][False]
'one'
>>> ['one', 'two'][True]
'two'
>>> True/20
0.05

This was for historical reasons: compatibility with pre-2.3 APIs; and I understand it was kept from 2.3 to 2.7. (This was addressed in this question from 2011)

However, why is it still true in Python 3? I do not see any advantage to it. And there is no reason to keep that for backward compatibility: Python 3.0 was a breaking release; and I don't think any pre-2.3 API is still around anyway.

MSeifert
  • 145,886
  • 38
  • 333
  • 352
Valentin Lorentz
  • 9,556
  • 6
  • 47
  • 69
  • Why do you think it was only kept for backwards-compatibility? Also note that Python3 wasn't intended as the "big breaking release", lots of the breaking changes were either accidental or at least unexpected. – MSeifert Jan 17 '18 at 20:38
  • 2
    The example you gave is not really "casting" to integers. Any class that implements `__index__` can do the same. – wim Jan 17 '18 at 20:45
  • Personally I don't see and dis-advantage to it. If you really *want* to use a `bool` as an `int`, then go ahead. Why change it unless there is a good reason? If you have a good reason then maybe you should add it to your question. – cdarke Jan 17 '18 at 20:45
  • 1
    Question to your question: What's the harm? The compatibility breaks in Python 3 were generally made only when the the old behavior was problematic or confusing. What is the harm of `bool` behaving as a number? There are legit uses, e.g. `sum(x % 2 == 0 for x in someseq)` as a way of counting even numbers (substitute whatever boolean test you like). I frequently count that way (sometimes it's `cnt += booleantest(someval)` in a normal `for` loop), because it happens to be convenient; sure, `if booleantest(someval): cnt += 1` also works, but why eliminate the option? – ShadowRanger Jan 17 '18 at 20:48
  • @ShadowRanger I reckon `sum(1 for x in someseq if x%2 == 0)` is more Pythonic, but opinions differ. – wim Jan 17 '18 at 21:17
  • @ShadomRanger I don't think there is harm, it's just a question that came up in a conversation with a friend about language quirks – Valentin Lorentz Jan 17 '18 at 21:17
  • @wim: I agree (I believe explicit `1` after test is faster on multiple levels too), but they're both fine. A lot of code assumes `bool`s are numerically 0 or 1, and violating that expectation to needlessly break code for no real benefit would be pointlessly harmful. – ShadowRanger Jan 17 '18 at 22:21

2 Answers2

8

From the original bool PEP:

Should we strive to eliminate non-Boolean operations on bools in the future, through suitable warnings, so that for example True+1 would eventually (in Python 3000) be illegal?

=> No.

There's a small but vocal minority that would prefer to see "textbook" bools that don't support arithmetic operations at all, but most reviewers agree with me that bools should always allow arithmetic operations.

And later in the same document:

Because of backwards compatibility, the bool type lacks many properties that some would like to see. For example, arithmetic operations with one or two bool arguments is allowed, treating False as 0 and True as 1. Also, a bool may be used as a sequence index.

I don't see this as a problem, and I don't want evolve the language in this direction either. I don't believe that a stricter interpretation of "Booleanness" makes the language any clearer.

Removing bools-as-numbers was not an intended language direction. Guido didn't think it'd make the language better.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • And this leads to Union[int, bool] being equal to "int", which means typing stuff gets broken. – LtWorf Jul 09 '19 at 14:12
1

Usefulness example: The two Boolean values 0, False and 1, True can represent the 2 parts of any binary partition. Suppose n people answer m questions and their response to each question is labelled 'fail' or 'pass'. We create a data table with n rows and m (+1, for id) columns and code fail/pass as 0/1. We can then count the passes for each question by summing rows and the passes for each question by summing columns. Any decent analysis software should be able to do this little or no custom programming.

Python 3 development: I participated in the discussion and am sure that there were many more compatibility breaking proposals rejected than accepted. Each change had to pay for itself.

Terry Jan Reedy
  • 18,414
  • 3
  • 40
  • 52