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
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.
Anyway, thanks for the response.
Oktay
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.
Terry Jan Reedy
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.
> 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.
Terry Jan Reedy
No, it wouldn't. We are talking about integer-boolean equality
comparisons, not boolean-string ones. But I get your point.
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!
Oktay
> 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.
--
Steven