Python boolean operator membership test with integer enumerator
Asked Answered
B

2

5

i was testing the precedence of comparison and membership operator, as per Python documentation they are at same precedence. But it is showing strange results as follows,

If anyone can justify following code and the corresponding output..

print( ( True!= 12) in (12,14))  #output: False
print( True!= 12 in (12,14))  #output: True
print( True!= (12 in (12,14)))  #output: False
Bribery answered 3/2, 2020 at 16:11 Comment(0)
A
5

From https://docs.python.org/3/reference/expressions.html:

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.

In the Comparisons section we find:

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, your second line is equivalent to:

True != 12 and 12 in (12, 14)

which evaluates to True and True which evaluates to True.

Similarly curious constructions are:

>>> True == True in (True, False)
True

>>> True == False in (True, False)
False

>>> 2 == 2 in (2, 3)
True

>>> 1 == 1 in (2, 3)
False

>>> 1 != 2 in (2, 3)
True

>>> 2 != 1 in (2, 3)
False

>>> 2 in (2, 3) in [True, False]
False
Aeroscope answered 25/10, 2020 at 21:21 Comment(2)
Thanks for your answer. I have read the docs, but because of the common x < y < z example I wrongly thought the chaining feature only applied to ordering operators.Siena
Thanks @progmatico! I agree that x < y < z seems like a "natural" thing. On the other hand, chaining inclusion test seems, at least to me, unnatural. For example, 2 in (2, 3) in [True, False] does not return what I would expect (I will add this example to the oddity list).Aeroscope
P
3

First Case:

print((True != 12) in (12,14))

We can say that first we evaluate True != 12 condition which give us True, and then we are evaluating if True is in the tuple (12,14) and that's False.

Third Case:

print(True != (12 in (12,14)))

We can say that first we evaluate (12 in (12,14)) condition which give us True because 12 is in the tuple (12,14). Then we evaluate if True != True an that's False.

Second Case:

print( True != 12 in (12,14))

So here is the tricky one. Without the parentheses we don't have where to start evaluating the conditions. To explain this case, I'm gonna give you the next example: if you try the following code (which is pretty similar to the one that we are trying to figure out the result):

print(1 != 2 != 3) #output True

You are gonna get True and that's because 1 != 2 and 2 != 3. So as you may have already noticed, it's an implicit AND. The above code is equal to:

print(1 != 2 and 2 != 3) #output True

So if we take this logic to our case, we are evaluating this:

print( True != 12 and 12 in (12,14)) # => (True and True) #output True
Puklich answered 25/10, 2020 at 21:19 Comment(4)
Thank you for your explanation. Note that you should be using the and operator and not the bitwise &. Otherwise things might get worse: 1 & 2 is 0 while 1 and 2 is 2.Siena
You are right, I should use the and operator, I think I am more used to the & from other programming languages. Nevertheless, things don't get worse because relational operations take precedence over logical operation. So, 1 != 2 will give us True and 2 != 3 gives True and we end up with True & True = True.Puklich
Sorry for not being clear. Things would get worse to understand if someone read your answer and starts using & as the and operator in Python. Of course I understood what you meant and it did not affect this particular case. I see you already fixed it, but we cannot upvote twice :)Siena
Ahhh yes totally! It's ok, I'm not here for the points :DPuklich

© 2022 - 2024 — McMap. All rights reserved.