I just came across some python code with the following statement:
if a==b in [c,d,e]:
...
It turns out that:
>>> 9==9 in [1,2,3]
False
>>> 9==9 in [1,2,3,9]
True
>>> (9==9) in [1,2,3,9]
True
>>> 9==(9 in [1,2,3,9])
False
>>> True in [1,2,3,9]
True
>>> True in []
False
>>> False in []
False
>>> False in [1,2,3]
False
Am I right in assuming that a==b in [c,d,e] is equivalent to (a==b) in [c,d,e] and therefore only really makes sense if [c,d,e] is a list of True/False values?
And in the case of the code I saw b is always in the list [c,d,e]. Would it then be equivalent to simply using a==b?
CodePudding user response:
Am I right in assuming that
a==b in [c,d,e]is equivalent to(a==b) in [c,d,e]
No. Since both == and in are comparison operators, the expression
a == b in [c, d, e]
is equivalent to
(a == b) and (b in [c, d, e])
since all comparison operators have the same precedence but can be chained.
and therefore only really makes sense if
[c,d,e]is a list ofTrue/Falsevalues?
It can also make sense to check if a boolean value is contained in a list of integers. Since True is considered equivalent to 1, and False is considered equivalent to 0 (see The standard type hierarchy), the result of this check can even be True.
CodePudding user response:
Just to throw another factor into the mix, operator chaining needs to be kept in mind as well:
Formally, if a, b, c, …, y, z are expressions and op1, op2, …, opN are comparison operators, then a op1 b op2 c ... y opN z is equivalent to a op1 b and b op2 c and ... y opN z, except that each expression is evaluated at most once.
The docs there specify "comparison operators", but later down is the addition:
Note that comparisons, membership tests, and identity tests, all have the same precedence and have a left-to-right chaining feature as described in the Comparisons section.
9==9 in [1,2,3,9] is confusingly the same as 9==9 and 9 in [1, 2, 3, 9].
CodePudding user response:
It seems like what is happening here, is that python interprets the values 1, 1.0, True all as equal in this case. So as long as the 1 is present in the list, the in operator returns True when comparing against a statement that compiles to True.
CodePudding user response:
a == b in [c,d,e] means ( a == b ) and (b in [c,d,e])
True in [1,2,3] means 1 in [1,2,3] (True == 1)
False in [0] means 0 in [0] (False == 0)
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).
Formally, if a, b, c, …, y, z are expressions and op1, op2, …, opN are comparison operators, then a op1 b op2 c ... y opN z is equivalent to a op1 b and b op2 c and ... y opN z, except that each expression is evaluated at most once.
Note that a op1 b op2 c doesn’t imply any kind of comparison between a and c, so that, e.g., x < y > z is perfectly legal (though perhaps not pretty).
The new Assignment expression (:=) operator from Python 3.8 onwards has the lowest precedence while parentheses() have the highest precedence.
| Operator | Description |
|---|---|
| := | Assignment expression (Lowest precedence) |
| lambda | Lambda expression |
| if-else | Conditional expression |
| or | Boolean OR |
| and | Boolean AND |
| not x | Boolean NOT |
| <, <=, >, >=, | Comparison operators |
| !=, == | Equality operators |
| in, not in, is, is not, | Identity operators, membership |
| | | Bitwise OR |
| ^ | Bitwise XOR |
| & | Bitwise AND |
| <<, >> | Left and right Shifts |
| , – | Addition and subtraction |
| *, @, /, //, % | Multiplication, matrix multiplication, division, floor division, remainder |
| x, -x, ~x | Unary plus, Unary minus, bitwise NOT |
| ** | Exponentiation |
| await x | Await expression |
| x[index], x[index:index], x(arguments…), x.attribute | Subscription, slicing, call, attribute reference |
| (expressions…), [expressions…],{key: value…}, {expressions…} | Binding or parenthesized expression, list display, dictionary display, set display |
| () | Parentheses (Highest precedence) |
