This question already has answers here:
Why does the expression 0 < 0 == 0 return False in Python?
(9 answers)
Closed 1 year ago.
why python 3 evaluate 3 in [] == False to be False?
But I know (3 in []) == False is True.
This is caused by chained comparisons
Unlike C, all comparison operations in Python have the same priority,
which is lower than that of any arithmetic, shifting or bitwise
operation. Also unlike C, expressions like a < b < c have the
interpretation that is conventional in mathematics:
comparison ::= or_expr (comp_operator or_expr)*
comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="
| "is" ["not"] | ["not"] "in"
Comparisons yield boolean values: True or False.
Comparisons can be chained arbitrarily, e.g., x < y <= z is equivalent
to x < y and y <= z, except that y is evaluated only once (but in both
cases z is not evaluated at all when x < y is found to be false).
Consider the case 1 < 2 < 3. This really breaks out to (1 < 2) and (2 < 3)
So the statement 3 in [] == False breaks out to (3 in []) and ([] == False)
Related
The Python documentation for operator precedence states:
Operators in the same box group left to right (except for
comparisons, including tests, which all have the same precedence and
chain from left to right — see section Comparisons...)
What does this mean? Specifically:
"Operators in the same box group left to right (except for
comparisons...)" -- do comparisons not group left to right?
If comparisons do not group left to right, what do they do instead? Do they "chain" as opposed to "group"?
If comparisons "chain" rather than "group", what is the difference between "chaining" and "grouping"?
What would be some examples to demonstrate that the comparison operators chain from left to right rather than from right to left?
Grouping (this is what non-comparison operators do):
a + b + c means (a + b) + c
Chaining (this is what comparison operators do):
a < b < c means (a < b) and (b < c)
Grouping left to right (this is the way things are grouped):
5 - 2 - 1 means (5 - 2) - 1 == 2
as opposed to grouping right to left (this would produce a different result):
5 - (2 - 1) == 4
Chaining left to right
Chaining is left to right, so in a < b < c, the expression a < b is evaluated before b < c, and if a < b is falsey, b < c is not evaluated.
(2 < 1 < f()) gives the value False without calling the function f, because 2 < 1 evaluates to false, so the second comparison does not need to be performed.
f() > 1 > g() calls f() in order to evaluate the first comparison, and depending on the result, it might or might not need to evaluate the second condition, which requires calling g().
NB. Each operand is evaluated at most once. So in the expression 1 < f() < 2, the function f() is only called once, and the value it gives is used in both comparisons (if necessary).
https://en.wikipedia.org/wiki/Short-circuit_evaluation
In fact, the chain behavior is not so obvious.
a == b == c
although one would expect this to be converted to
a == b and b == c
it is in fact converted into somthing similar to
b == c if a == b else False
which is a bit confusing if one tries to override the behavior of the comparison operators and chain them.
This question already has answers here:
python operator precedence of in and comparison [duplicate]
(3 answers)
Closed 2 years ago.
Suppose I have the following line of code:
print("valley" in "hillside" == False)
Since the precedence of in and == is equivalent in Python, I expected the operations to be performed from left to right, producing True as the output.
However, in actuality, when I run this line of code, I get False.
I have noticed that adding brackets around "valley" in "hillside" results in True as the output but I don't seem to understand why it's necessary in the first place...
Both in and == are comparison operators, so the parser treats
print("valley" in "hillside" == False)
the same as
print("valley" in "hillside" and "hillside" == False)
See the section on Comparisons in the Python language reference for more details, in particular this note:
Comparisons can be chained arbitrarily, e.g., x < y <= z is equivalent to x < y and y <= z, except that y is evaluated only once (but in both cases z is not evaluated at all when x < y is found to be false).
All comparison operations in Python have the same priority, which is lower than that of any arithmetic, shifting or bitwise operation. Thus "==" and "<" have the same priority, why would the first expression in the following evaluate to True, different from the 2nd expression?
>>> -1 < 0 == False
True
>>> (-1 < 0) == False
False
I would expect both be evaluated to False. Why is it not the case?
Python has a really nice feature - chained comparison, like in math expressions, so
-1 < 0 == False
is actually a syntactic sugar for
-1 < 0 and 0 == False
under the hood.
This question already has answers here:
What does it mean that Python comparison operators chain/group left to right?
(2 answers)
Why does the expression 0 < 0 == 0 return False in Python?
(9 answers)
Where in the python docs does it allow the `in` operator to be chained?
(1 answer)
Closed 5 years ago.
I just stumbled upon the following line in Python 3.
1 in range(2) == True
I was expecting this to be True since 1 in range(2) is True and True == True is True.
But this outputs False. So it does not mean the same as (1 in range(2)) == True. Furthermore it does not mean the same as 1 in (range(2) == True) which raises an error.
Despite years of experience in Python, I am taken off guard. What is going on?
This is due to the fact that both operators are comparison operators, so it is being interpreted as operator chaining:
https://docs.python.org/3.6/reference/expressions.html#comparisons
Comparisons can be chained arbitrarily, e.g., x < y <= z is equivalent
to x < y and y <= z, except that y is evaluated only once (but in both
cases z is not evaluated at all when x < y is found to be false).
So it is equivalent to:
>>> (1 in range(2)) and (range(2) == True)
False
Coming from a Java background into Python and working my way through CodingBat (Python > Warmup-1 > pos_neg) the following confused me greatly:
>>> True ^ False
True
>>> 1<0 ^ -1<0
False
I appreciate the following:
>>> (1<0) ^ (-1<0)
True
But what is python interpreting 1<0 ^ -1<0 as to return false?
^ has higher precedence than <.
Thus, what is being evaluated is actually 1 < -1 < 0, where 0 ^ -1 = -1
And thus you rightly get False, since the inequality clearly does not hold.
You almost never have to remember the precedence table. Just neatly use parenthesis.
You might want to check this out as well, which discusses an identical situation.
0 ^ -1 equals -1. 1 < -1 < 0 is False since 1 is greater than -1. Python chains relational operators naturally, hence 1 < -1 < 0 is equivalent to (1 < -1) and (-1 < 0).