You're mixing two concepts: equality testing and truth-value testing. They are not the same in Python.
I think what triggered the question is that Python does an implicit casting when you do if something
(it casts the something to bool
) but it does not do implicit casting when you do something1 == something2
.
Pythons data model actually explains how these operations are done:
- It starts by checking if the object implements the
__bool__
method and if it does it uses the returned boolean.
- If it doesn't define a
__bool__
method it looks at the __len__
method. If it's implemented it will use the result of len(obj) != 0
.
- If it doesn't have either the object is considered
True
.
For integers the __bool__
method returns True
except when the integer value is 0
(then it's False
).
The Ellipsis object (...
is the Ellipsis object) on the other hand doesn't implement __bool__
or __len__
so it's always True
.
Equality testing relies on the __eq__
method of both arguments. It's more a chain of operations:
- It checks if the first operand implements
__eq__
when the second operand is passed as argument.
- If it doesn't then it checks if the second operand implements
__eq__
when the first operand is passed as argument.
- If it doesn't then Python checks for object identity (if they are the same object - similar to pointer comparisons in C-like languages)
The order of these operations may vary.1
For built-in Python types these operations are explicitly implemented. For example int
egers implement __eq__
but the CHECK_BINOP
makes sure that it returns NotImplemented
if the other one isn't an int
eger.
The Ellipsis
object doesn't implement __eq__
at all.
So when you compare integers and Ellipsis Python will always fallback to object identity and so it will always return False
.
On the other hand bool
eans are a subclass of int
egers so they actually compare with int
(they are another int
after all). The booleans are implemented as 1
(True
) and 0
(False
). So they compare equal:
>>> 1 == True
True
>>> 0 == False
True
>>> 1 == False
False
>>> 0 == True
False
Even though the source code is probably hard to understand I hope I explained the concepts well enough (the source code is for the CPython implementation, the implementation in other Python implementations like PyPy, IronPython may differ!). The important take-away message should be that Python doesn't do implicit conversions in equality checks and equality testing is not related to truth value testing at all. The built-in types are implemented that they almost always give senseable results:
- all number-types implement equality in some way (floats compare to integers, complex compare to integers and floats)
- and everything not-zero and not-empty is
truthy
.
However if you create your own classes you can override equality and truth value testing as you like (and then you can spread a lot of confusion)!
1 In some cases the order is changed:
- If the second operand is a subclass of the first operand the first two steps are reversed.
- For some implicit equality checks the object identity is checked before any
__eq__
methods are called. For example when checking if some item is in a list, i.e. 1 in [1,2,3]
.
bool(...) == True
-->True
– Keeneybool(...)
returnsTrue
– OhgTrue
with being equal toTrue
. Python booleans areints
,1 == True
and0 == False
, but any(?) non-empty non-zero object evaluates toTrue
, as you can see withbool()
– Cretan1 == True
is becausebool
inherits fromint
. Whether this is a good idea or not (cf Ruby) it's unlikely to change in Python. For this reason you should get into the habit of usingx is True
,x is False
, orx is None
for those situations. – Marna