Why does the expression 0 < 0 == 0 return False in Python?
Looking into Queue.py in Python 2.6, I found this construct that I found a bit strange:
def full(self):
"""Return True if the queue is full, False otherwise
(not reliable!)."""
self.mutex.acquire()
n = 0 < self.maxsize == self._qsize()
self.mutex.release()
return n
If maxsize
is 0 the queue is never full.
My question is how does it work for this case? How 0 < 0 == 0
is considered False?
>>> 0 < 0 == 0
False
>>> (0) < (0 == 0)
True
>>> (0 < 0) == 0
True
>>> 0 < (0 == 0)
True
Solution 1:
I believe Python has special case handling for sequences of relational operators to make range comparisons easy to express. It's much nicer to be able to say 0 < x <= 5
than to say (0 < x) and (x <= 5)
.
These are called chained comparisons. And that's a link to the documentation for them.
With the other cases you talk about, the parenthesis force one relational operator to be applied before the other, and so they are no longer chained comparisons. And since True
and False
have values as integers you get the answers you do out of the parenthesized versions.
Solution 2:
Because
(0 < 0) and (0 == 0)
is False
. You can chain together comparison operators and they are automatically expanded out into the pairwise comparisons.
EDIT -- clarification about True and False in Python
In Python True
and False
are just instances of bool
, which is a subclass of int
. In other words, True
really is just 1.
The point of this is that you can use the result of a boolean comparison exactly like an integer. This leads to confusing things like
>>> (1==1)+(1==1)
2
>>> (2<1)<1
True
But these will only happen if you parenthesise the comparisons so that they are evaluated first. Otherwise Python will expand out the comparison operators.
Solution 3:
The strange behavior your experiencing comes from pythons ability to chain conditions. Since it finds 0 is not less than 0, it decides the entire expression evaluates to false. As soon as you break this apart into seperate conditions, you're changing the functionality. It initially is essentially testing that a < b && b == c
for your original statement of a < b == c
.
Another example:
>>> 1 < 5 < 3
False
>>> (1 < 5) < 3
True
Solution 4:
>>> 0 < 0 == 0
False
This is a chained comparison. It returns true if each pairwise comparison in turn is true. It is the equivalent to (0 < 0) and (0 == 0)
>>> (0) < (0 == 0)
True
This is equivalent to 0 < True
which evaluates to True.
>>> (0 < 0) == 0
True
This is equivalent to False == 0
which evaluates to True.
>>> 0 < (0 == 0)
True
Equivalent to 0 < True
which, as above, evaluates to True.