
I bumped into this today by accident and I can't recall ever being aware of this. Why isn't this a TypeError in Python 3? -- Giampaolo - http://grodola.blogspot.com

On Mon, Jun 6, 2016 at 2:37 AM, Giampaolo Rodola' <g.rodola@gmail.com> wrote:
Because it's a good thing. bool is a subclass of int, True is exactly 1, False is exactly 0. You can sum a series of conditions and get the number that are true, for instance. There's no point doing this: sum(1 if x < 5 else 0 for x in stuff) when you can just do this: sum(x < 5 for x in stuff) to quickly count the values that fit some condition. ChrisA

On Sun, Jun 05, 2016 at 06:37:48PM +0200, Giampaolo Rodola' wrote:
Because bool is a subclass of int, and has been since it was first introduced back in Python 2.2. I'm not quite sure what your question is about... are you asking what was the original justification for making True and False equal to 1 and 0? If so, see the PEP: https://www.python.org/dev/peps/pep-0285/ Or do you mean to ask why it wasn't changed in Python 3? Well, changed to what? All the reasons given in the PEP still hold, and there's no really compelling reason to make bool something else. Since bools aren't broken, why change them? -- Steve

On Sun, Jun 5, 2016 at 7:23 PM, Steven D'Aprano <steve@pearwood.info> wrote:
I've read through the PEP and I understand the rationale about why True/False is a subclass of int and I'm OK with that. PEP-285 at chapter 6 suggests a strong practical reason for this: * In an ideal world, bool might be better implemented as a* * separate integer type that knows how to perform mixed-mode* * arithmetic. However, inheriting bool from int eases the* * implementation enormously (in part since all C code that calls* * PyInt_Check() will continue to work -- this returns true for* * subclasses of int)* What I find odd though is that a bool can be used in arithmetical operations as if it was the exact same thing as a number. I mean, to me this is just odd:
1 + True 2
I would have expected that to be treated the same as:
A bool may be a subclass of int but conceptually (to me at least) it's different almost the same way "1" is different than 1. I say "almost" only because bool is a subclass of int, but then again, to my understanding that was done for practical reasons (implementation details), not because the main intention was to explicitly allow mixing bools and numbers in arithmetical operations. On the other hand (and I'm gonna contradict myself with what I've just said above) on chapter 4: * 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.* ...so maybe supporting arithmetical operations was also a primary intention, in which case my question is "why?". -- Giampaolo - http://grodola.blogspot.com

On 5 Jun 2016 11:38, "Giampaolo Rodola'" <g.rodola@gmail.com> wrote:
On the other hand (and I'm gonna contradict myself with what I've just
said above) on chapter 4:
intention, in which case my question is "why?". The inheritance from int meant the default behaviour was to support type-promoting integer arithmetic operations in addition to bitwise arithmetic. That changes the question from "Why support that?" to "Why do the extra design, documentation and implementation work needed to prevent that?". The fact that "1 + True == 2" is surprising hasn't proven to be enough to motivate anyone to define the precise subset of operations they want to prevent, and then make the case for those restrictions as Python's native behaviour. Cheers, Nick.

On 6/5/2016 2:37 PM, Giampaolo Rodola' wrote:
'subclass of int' means 'instances are ints'
What I find odd though is that a bool can be used in arithmetical operations as if it was the exact same thing as a number.
That is what subclass means.
This would only be sensible if Bools were strings.
For some people, yes.
in which case my question is "why?".
Just a few days ago, I read someone, while discussing an fairly large application, saying how nice python is because it allows simple code like score = sum(s==c for s, c in zip(student, correct)) (This is not the code from the application, but close enough.) There is real code in the wild exploiting issubclass(bool, int), which could be broken if that were changed. -- Terry Jan Reedy

On Jun 5, 2016 9:20 PM, "Terry Reedy" <tjreedy@udel.edu> wrote:
aware of
Some of that reply is too pedantic, like the part about `1+"1"`. Discuss what people are _trying_ to say, at least in addition to what they actually say. Anyway, I'd argue that, from a purity standpoint, summing an iterator of bools is hacky, and what you really want is this: # Count student answers that match the respective correct answers. count(s for s, c in zip(student, correct) if s == c) (Alas, the library for iterator operations, `itertools`, already has a very different function named `count`.) But I'm not pushing for non-int bools. Purity is not a primary Python principle. Python has `if lst:` for emptiness, and I doubt that will ever go away. (Though it makes Numpy arrays needlessly incompatible with some libraries.) Int-like bools can also be used for: - Hacky `if-else`: # Works for numbers, strs, lists, tuples, bytess, and bytearrays! (x == y)*yes + (x != y)*no - Hacky `if-else`: yes**(x == y) * no**(x != y) - Hacky `if-else`: [no, yes][x==y] - Hacky `if-else`: (x == y and [yes] or [no])[0] - Hacky `if/if-not` (control flow): (x == y) > 0 > (print("yes") or 1) (x == y) < 1 < (print("no") or 0) - Generalization of XOR: "Exactly N out of M conditions hold." * Fourth example from: https://mail.python.org/pipermail/python-dev/2002-March/020835.html Earlier discussions: - 2002 March: PEP 285 review. https://mail.python.org/pipermail/python-dev/2002-March/020750.html - 2002 March: Against int subclassing in PEP 285. https://mail.python.org/pipermail/python-list/2002-March/129054.html - 2015 January: Against int subclassing. https://mail.python.org/pipermail/python-ideas/2015-January/031233.html

On 2016-06-05 14:37, Giampaolo Rodola' wrote:
When using something like NumPy or Pandas or related packages, it is quite common and useful to compute the sum of a boolean vector to check how many elements pass some criterion: """ In [1]: import numpy as np In [2]: A = np.random.randn(25) In [3]: A Out[3]: array([-1.20821997, 0.8731083 , 0.68458201, 1.86704545, 0.67679372, -0.63936162, -1.2518435 , -0.55477108, 0.00940205, 1.61347396, 1.51399244, 0.57676897, 0.86984802, 0.96965798, -0.0726013 , -0.35246648, 0.12149487, -0.42062617, -0.22227402, -0.3525525 , -1.04447944, -0.39717087, -0.23223961, 0.81008826, 0.34763992]) In [4]: A > 0 Out[4]: array([False, True, True, True, True, False, False, False, True, True, True, True, True, True, False, False, True, False, False, False, False, False, False, True, True], dtype=bool) In [5]: (A > 0).sum() Out[5]: 13 """ It's true that none of this behavior strictly depends on the behavior of the Python bool object -- the behavior of NumPy arrays already diverges quite a bit from Python lists and built-in data types, so this behavior would probably still be part of NumPy even if arithmetic operations on Python bools raised a TypeError. This is still a good example of why it can be very useful to have True + True + False == 2, though. MMR...

On Mon, Jun 6, 2016 at 2:37 AM, Giampaolo Rodola' <g.rodola@gmail.com> wrote:
Because it's a good thing. bool is a subclass of int, True is exactly 1, False is exactly 0. You can sum a series of conditions and get the number that are true, for instance. There's no point doing this: sum(1 if x < 5 else 0 for x in stuff) when you can just do this: sum(x < 5 for x in stuff) to quickly count the values that fit some condition. ChrisA

On Sun, Jun 05, 2016 at 06:37:48PM +0200, Giampaolo Rodola' wrote:
Because bool is a subclass of int, and has been since it was first introduced back in Python 2.2. I'm not quite sure what your question is about... are you asking what was the original justification for making True and False equal to 1 and 0? If so, see the PEP: https://www.python.org/dev/peps/pep-0285/ Or do you mean to ask why it wasn't changed in Python 3? Well, changed to what? All the reasons given in the PEP still hold, and there's no really compelling reason to make bool something else. Since bools aren't broken, why change them? -- Steve

On Sun, Jun 5, 2016 at 7:23 PM, Steven D'Aprano <steve@pearwood.info> wrote:
I've read through the PEP and I understand the rationale about why True/False is a subclass of int and I'm OK with that. PEP-285 at chapter 6 suggests a strong practical reason for this: * In an ideal world, bool might be better implemented as a* * separate integer type that knows how to perform mixed-mode* * arithmetic. However, inheriting bool from int eases the* * implementation enormously (in part since all C code that calls* * PyInt_Check() will continue to work -- this returns true for* * subclasses of int)* What I find odd though is that a bool can be used in arithmetical operations as if it was the exact same thing as a number. I mean, to me this is just odd:
1 + True 2
I would have expected that to be treated the same as:
A bool may be a subclass of int but conceptually (to me at least) it's different almost the same way "1" is different than 1. I say "almost" only because bool is a subclass of int, but then again, to my understanding that was done for practical reasons (implementation details), not because the main intention was to explicitly allow mixing bools and numbers in arithmetical operations. On the other hand (and I'm gonna contradict myself with what I've just said above) on chapter 4: * 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.* ...so maybe supporting arithmetical operations was also a primary intention, in which case my question is "why?". -- Giampaolo - http://grodola.blogspot.com

On 5 Jun 2016 11:38, "Giampaolo Rodola'" <g.rodola@gmail.com> wrote:
On the other hand (and I'm gonna contradict myself with what I've just
said above) on chapter 4:
intention, in which case my question is "why?". The inheritance from int meant the default behaviour was to support type-promoting integer arithmetic operations in addition to bitwise arithmetic. That changes the question from "Why support that?" to "Why do the extra design, documentation and implementation work needed to prevent that?". The fact that "1 + True == 2" is surprising hasn't proven to be enough to motivate anyone to define the precise subset of operations they want to prevent, and then make the case for those restrictions as Python's native behaviour. Cheers, Nick.

On 6/5/2016 2:37 PM, Giampaolo Rodola' wrote:
'subclass of int' means 'instances are ints'
What I find odd though is that a bool can be used in arithmetical operations as if it was the exact same thing as a number.
That is what subclass means.
This would only be sensible if Bools were strings.
For some people, yes.
in which case my question is "why?".
Just a few days ago, I read someone, while discussing an fairly large application, saying how nice python is because it allows simple code like score = sum(s==c for s, c in zip(student, correct)) (This is not the code from the application, but close enough.) There is real code in the wild exploiting issubclass(bool, int), which could be broken if that were changed. -- Terry Jan Reedy

On Jun 5, 2016 9:20 PM, "Terry Reedy" <tjreedy@udel.edu> wrote:
aware of
Some of that reply is too pedantic, like the part about `1+"1"`. Discuss what people are _trying_ to say, at least in addition to what they actually say. Anyway, I'd argue that, from a purity standpoint, summing an iterator of bools is hacky, and what you really want is this: # Count student answers that match the respective correct answers. count(s for s, c in zip(student, correct) if s == c) (Alas, the library for iterator operations, `itertools`, already has a very different function named `count`.) But I'm not pushing for non-int bools. Purity is not a primary Python principle. Python has `if lst:` for emptiness, and I doubt that will ever go away. (Though it makes Numpy arrays needlessly incompatible with some libraries.) Int-like bools can also be used for: - Hacky `if-else`: # Works for numbers, strs, lists, tuples, bytess, and bytearrays! (x == y)*yes + (x != y)*no - Hacky `if-else`: yes**(x == y) * no**(x != y) - Hacky `if-else`: [no, yes][x==y] - Hacky `if-else`: (x == y and [yes] or [no])[0] - Hacky `if/if-not` (control flow): (x == y) > 0 > (print("yes") or 1) (x == y) < 1 < (print("no") or 0) - Generalization of XOR: "Exactly N out of M conditions hold." * Fourth example from: https://mail.python.org/pipermail/python-dev/2002-March/020835.html Earlier discussions: - 2002 March: PEP 285 review. https://mail.python.org/pipermail/python-dev/2002-March/020750.html - 2002 March: Against int subclassing in PEP 285. https://mail.python.org/pipermail/python-list/2002-March/129054.html - 2015 January: Against int subclassing. https://mail.python.org/pipermail/python-ideas/2015-January/031233.html

On 2016-06-05 14:37, Giampaolo Rodola' wrote:
When using something like NumPy or Pandas or related packages, it is quite common and useful to compute the sum of a boolean vector to check how many elements pass some criterion: """ In [1]: import numpy as np In [2]: A = np.random.randn(25) In [3]: A Out[3]: array([-1.20821997, 0.8731083 , 0.68458201, 1.86704545, 0.67679372, -0.63936162, -1.2518435 , -0.55477108, 0.00940205, 1.61347396, 1.51399244, 0.57676897, 0.86984802, 0.96965798, -0.0726013 , -0.35246648, 0.12149487, -0.42062617, -0.22227402, -0.3525525 , -1.04447944, -0.39717087, -0.23223961, 0.81008826, 0.34763992]) In [4]: A > 0 Out[4]: array([False, True, True, True, True, False, False, False, True, True, True, True, True, True, False, False, True, False, False, False, False, False, False, True, True], dtype=bool) In [5]: (A > 0).sum() Out[5]: 13 """ It's true that none of this behavior strictly depends on the behavior of the Python bool object -- the behavior of NumPy arrays already diverges quite a bit from Python lists and built-in data types, so this behavior would probably still be part of NumPy even if arithmetic operations on Python bools raised a TypeError. This is still a good example of why it can be very useful to have True + True + False == 2, though. MMR...
participants (7)
-
Chris Angelico
-
Franklin? Lee
-
Giampaolo Rodola'
-
Matt Ruffalo
-
Nick Coghlan
-
Steven D'Aprano
-
Terry Reedy