> After some head scratching, I realized that: > - bool is a subclass of int and that True and False evaluates to 1 and > 0, so -1 is equal to neither; and > - The if -1: statement probably works by treating -1 as bool(-1).
Yes.
> But I can't help finding the former comparison behavior odd. I admit > that it is odd to write such code but when someone writes -1 == True, > the intention is clearly a boolean comparison, not a numerical value > comparison, isn't it?
Not to me. The rules of Python state that the object on the left hand side is asked first how to compare the two values. Only if that fails is the object on the right hand side asked how to compare the objects.
> As far as I understand, to do this comparison, python is casting > (loosely speaking) True to its numerical value, rather than casting -1 > to its boolean value.
Not really. No casting goes on at all. bool is just one of the types that int.__eq__ knows how to handle because bool is a subclass of int. Vice-versa, bool.__eq__ knows how to handle ints, and it also does a numerical comparison; it never casts to a boolean.
> So, my question is: wouldn't it make more sense to do just the opposite, > i.e. cast -1 to its boolean value and do a boolean comparison of the > operands, when one of the operands is True or False?
> Or is this too fancy? What do you think?
I think that being explicit is better than being implicit. If you want to cast an object to a boolean, use bool() on it. Making special rules when comparing with booleans makes it harder to treat True and False as first-class objects.
-- Robert Kern
"I have come to believe that the whole world is an enigma, a harmless enigma that is made terrible by our own mad attempt to interpret it as though it had an underlying truth." -- Umberto Eco
>> After some head scratching, I realized that: >> - bool is a subclass of int and that True and False evaluates to 1 and >> 0, so -1 is equal to neither; and >> - The if -1: statement probably works by treating -1 as bool(-1).
> Yes.
Good.
>> But I can't help finding the former comparison behavior odd. I admit >> that it is odd to write such code but when someone writes -1 == True, >> the intention is clearly a boolean comparison, not a numerical value >> comparison, isn't it?
> Not to me. The rules of Python state that the object on the left hand > side is asked first how to compare the two values. Only if that fails is > the object on the right hand side asked how to compare the objects.
OK.
>> As far as I understand, to do this comparison, python is casting >> (loosely speaking) True to its numerical value, rather than casting -1 >> to its boolean value.
> Not really. No casting goes on at all.
Of course, I said loosely speaking.
> bool is just one of the types that int.__eq__ knows how to handle > because bool is a subclass of int. > Vice-versa, bool.__eq__ knows how to handle ints, and it also does a > numerical comparison; it never casts to a boolean.
That's what I'm trying to say: it would be more meaningful if int.__eq__ did a boolean comparison when the other operand is a boolean. And bool.__eq__ should as well do a boolean comparison when the other operand is an integer (or even a number). The reason is that when someone writes (-1 == True) he is clearly, definitely, absolutely asking for a boolean comparison, not a numerical one. As I said before, this is weird code; but using the True built-in for checking whether a number's value is equal to 1 would be even weirder.
>> So, my question is: wouldn't it make more sense to do just the opposite, >> i.e. cast -1 to its boolean value and do a boolean comparison of the >> operands, when one of the operands is True or False?
>> Or is this too fancy? What do you think?
> I think that being explicit is better than being implicit.
Well, I agree that explicit is better than implicit: when one wants to use the numerical values of True or False, he should make it explicit and use int(True) or int(False), but one is never interested in a boolean's numerical value (which is nonsense, IMHO). We never write counter += True, for example.
> If you want to cast an object to a boolean, use bool() on it.
Well, I can tell you in response that if you are interested in a boolean's *integer* value, than make it explicit and use int(True). When I write
assert i == True
I'm not trying to make sure that i is equal to one, I am trying to make sure that it evaluates to True (of course True is redundant here but it can make the code more readable). If I was interested in the former case, it would be most natural to write assert i == 1 but I'm interested in the latter and I think Python's treatment is not quite right here.
> Making special rules when comparing with booleans makes it harder to > treat True and False as first-class objects.
I don't see how fixing this makes harder to treat True and False as first-class objects. If doing the right thing takes some special casing then be it, but I don't think it's so.
> After some head scratching, I realized that: > - bool is a subclass of int and that True and False evaluates to 1 and > 0,
Yes, for historical and practical reasons.
> so -1 is equal to neither; and
NO builtin objects other than numbers equal to 1 or 0 are equal to True or False.
> - The if -1: statement probably works by treating -1 as bool(-1).
'if condition:' *always* works by calling bool() on the condition, which is why one should *never* write 'if bool(exp):'.
> But I can't help finding the former comparison behavior odd.
Every object other than numbers equal to 0 or 1 has the same behavior.
> I admit that it is odd to write such code but when someone writes -1 == True,
It is odd to write such code because the result of comparing two constants is or could be known when it is written. So while one could write an optimizer to replace such comparisons with the known value at compile time, no one has done so. (There is an optimizer that sometimes replaces arithmetic operations on number constants, but that is because writing code that way may make it clearer: for instance, 1<<13 versus 8192.)
> the intention is clearly a boolean comparison, not a numerical value > comparison, isn't it?
Nope. Expecially if either side of the expression in the code is a name or collection slot. As far as the compiler is concerned, '-1' is an expression that evaluates to an object and 'True' is another expression that evaulates to another object and '==' is a comparison operator which it compiles to a call to code that calls the appropriate rich comparison methods of either or both of the two objects.
> As far as I understand, to do this comparison, python is casting > (loosely speaking) True to its numerical value, rather than casting -1 > to its boolean value.
I think that this is speaking so loosely as to be misleading. 'Cast' has a couple of meaning, neither of which means 'treat a subclass instance as a base class instance.' Subclass instances are automatically base class instances and are treated as such by default unless there is a subclass method that over-rides the base class method. Bool does *not* over-ride int comparison methods.
>>> bool.__eq__ is int.__eq__ True
I suspect that the only methods to bool are __new__ (which returns one of the only two instances allowed), __str__, and __repr__ (which return 'False' or 'True' instead of '0' or '1'). Bools are ints, not 'cast to' ints.
> So, my question is: wouldn't it make more sense to do just the opposite, > i.e. cast -1 to its boolean value and do a boolean comparison of the > operands, when one of the operands is True or False?
That would require that ints be subclassed from bool, which does not work.
>>> This works though: >>> >>> if -1: >>> print "OK"
>>> OK
>>> After some head scratching, I realized that: >>> - bool is a subclass of int and that True and False evaluates to 1 and >>> 0, so -1 is equal to neither; and >>> - The if -1: statement probably works by treating -1 as bool(-1).
>> Yes.
> Good.
>>> But I can't help finding the former comparison behavior odd. I admit >>> that it is odd to write such code but when someone writes -1 == True, >>> the intention is clearly a boolean comparison, not a numerical value >>> comparison, isn't it?
>> Not to me. The rules of Python state that the object on the left hand >> side is asked first how to compare the two values. Only if that fails >> is the object on the right hand side asked how to compare the objects.
> OK.
>>> As far as I understand, to do this comparison, python is casting >>> (loosely speaking) True to its numerical value, rather than casting -1 >>> to its boolean value.
>> Not really. No casting goes on at all.
> Of course, I said loosely speaking.
>> bool is just one of the types that int.__eq__ knows how to handle >> because bool is a subclass of int. Vice-versa, bool.__eq__ knows how >> to handle ints, and it also does a numerical comparison; it never >> casts to a boolean.
> That's what I'm trying to say: it would be more meaningful if int.__eq__ > did a boolean comparison when the other operand is a boolean. And > bool.__eq__ should as well do a boolean comparison when the other > operand is an integer (or even a number). The reason is that when > someone writes (-1 == True) he is clearly, definitely, absolutely asking > for a boolean comparison, not a numerical one. As I said before, this is > weird code; but using the True built-in for checking whether a number's > value is equal to 1 would be even weirder.
So don't do it. There really aren't many use cases for comparing with a boolean. Just call bool() on the object.
>>> So, my question is: wouldn't it make more sense to do just the opposite, >>> i.e. cast -1 to its boolean value and do a boolean comparison of the >>> operands, when one of the operands is True or False?
>>> Or is this too fancy? What do you think?
>> I think that being explicit is better than being implicit.
> Well, I agree that explicit is better than implicit: when one wants to > use the numerical values of True or False, he should make it explicit > and use int(True) or int(False), but one is never interested in a > boolean's numerical value (which is nonsense, IMHO). We never write > counter += True, for example.
Actually, I sum up booleans quite often.
>> If you want to cast an object to a boolean, use bool() on it.
> Well, I can tell you in response that if you are interested in a > boolean's *integer* value, than make it explicit and use int(True).
The two positions are not symmetrical. Your position requires special-casing equality testing; Python's position doesn't.
> When > I write
> assert i == True
> I'm not trying to make sure that i is equal to one, I am trying to make > sure that it evaluates to True (of course True is redundant here but it > can make the code more readable). If I was interested in the former > case, it would be most natural to write assert i == 1 but I'm interested > in the latter and I think Python's treatment is not quite right here.
Then just do "assert i" or "assert bool(i)" and be done with it. There's no need to do any comparisons at all.
> > Making special rules when comparing with booleans makes it harder to > > treat True and False as first-class objects.
> I don't see how fixing this makes harder to treat True and False as > first-class objects. If doing the right thing takes some special casing > then be it, but I don't think it's so.
True in ['something', False]
In your semantics, this would evaluate to True because ('something' == True) is True.
-- Robert Kern
"I have come to believe that the whole world is an enigma, a harmless enigma that is made terrible by our own mad attempt to interpret it as though it had an underlying truth." -- Umberto Eco
Oktay Şafak wrote: > That's what I'm trying to say: it would be more meaningful if int.__eq__ > did a boolean comparison when the other operand is a boolean.
For that to be done, int would have to know about its subclass, which generally is bad design.
> The reason is that when > someone writes (-1 == True) he is clearly, definitely, absolutely asking > for a boolean comparison, not a numerical one.
I would say that the person does not understand Python and that the code is probably buggy.
> As I said before, this is weird code;
It is a bad idea to accommodate the language and interpreter to weird code which should never be written.
> Well, I agree that explicit is better than implicit: when one wants to > use the numerical values of True or False, he should make it explicit > and use int(True) or int(False).
The reason to make bool a subclass of int is to avoid having to do that. You do not have to like this fact of Python but it has been decided and will not change.
> We never write counter += True, for example.
But you might write counter += name, where you know name is bound to a bool. As I said, issubclass(bool, int) just so one would not have to write counter += int(name).
>> If you want to cast an object to a boolean, use bool() on it. > Well, I can tell you in response that if you are interested in a > boolean's *integer* value, than make it explicit and use int(True).
A Python bool *is* an int already: isinstance(True, int) returns True! Adding the bool subclass around 2.3 or so was a convenience that makes code and output clearer, but not a necessity. Python did fine without it just as many other languages do.
>> I don't see how fixing this makes harder to treat True and False as >> first-class objects. If doing the right thing takes some special casing >> then be it, but I don't think it's so.
> True in ['something', False]
> In your semantics, this would evaluate to True because ('something' == > True) is True.
No, it wouldn't. We are talking about integer-boolean equality comparisons, not boolean-string ones. But I get your point.
>> That's what I'm trying to say: it would be more meaningful if >> int.__eq__ did a boolean comparison when the other operand is a boolean.
> For that to be done, int would have to know about its subclass, which > generally is bad design.
Good point, but of course it can be done without making the int type know about the specifics of its subclass.
>> The reason is that when someone writes (-1 == True) he is clearly, >> definitely, absolutely asking for a boolean comparison, not a >> numerical one.
> I would say that the person does not understand Python and that the code > is probably buggy.
> > As I said before, this is weird code;
> It is a bad idea to accommodate the language and interpreter to weird > code which should never be written.
Again, good point. Agreed.
>> Well, I agree that explicit is better than implicit: when one wants to >> use the numerical values of True or False, he should make it explicit >> and use int(True) or int(False).
> The reason to make bool a subclass of int is to avoid having to do that. > You do not have to like this fact of Python but it has been decided and > will not change.
> > We never write counter += True, for example.
> But you might write counter += name, where you know name is bound to a > bool. As I said, issubclass(bool, int) just so one would not have to > write counter += int(name).
OK, my fault. Arithmetical operations was not my point, I was just trying to talk about integer values of True and False in an equality comparison context with other numbers. Of course the fact that issubclass(bool, int) is very handy in calculations like that.
>>> If you want to cast an object to a boolean, use bool() on it.
>> Well, I can tell you in response that if you are interested in a >> boolean's *integer* value, than make it explicit and use int(True).
> A Python bool *is* an int already: isinstance(True, int) returns True!
I know, you don't need to shout. What I was trying to say is that using the integer value of a boolean *in a comparison with a number* doesn't make much sense *to me*. I am not trying to change Python or whatever, I am extremely pleased with it as it is. But that doesn't mean I like each and every decision that has gone into it. Like everybody else, there are things that doesn't quite fit in for me and I am trying to understand better. I just came across this behavior while trying something in the interpreter and wanted to discuss with people more knowledgeable than myself. Please keep calm!
On Sun, 25 Jan 2009 03:07:04 +0200, Oktay Şafak wrote: > The reason is that when > someone writes (-1 == True) he is clearly, definitely, absolutely asking > for a boolean comparison, not a numerical one.
If I wrote (-1 == True), and I'm not sure why I would, I would expect to get the answer False, because -1 is not equal to True. Many things have truth values which are true but not equal to True.
If I wanted bool(-1) == True, I'd write bool(-1) == True. Or, if I was in a whimsical mood, I'd write:
((bool(-1) == True) == True) == True # oh when to stop???
just to illustrate the foolishness of doing boolean equality comparisons like that.