Title: Inappropriate short circuit relating to inequality comparison and membership test
Type: behavior Stage: resolved
Components: Interpreter Core Versions: Python 3.8
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: Orion Fisher, eryksun, tim.peters
Priority: normal Keywords:

Created on 2020-02-25 03:08 by Orion Fisher, last changed 2020-02-25 03:53 by tim.peters. This issue is now closed.

File name Uploaded Description Edit Orion Fisher, 2020-02-25 03:08 example with bytecode
Messages (5)
msg362612 - (view) Author: Orion Fisher (Orion Fisher) Date: 2020-02-25 03:08
I found a strange issue with how the interpreter produces bytecode for an expression like True != True in [False, False].

Reading it, one would expect the value of the expression to be True, whether the inequality comparison is evaluated first, or the membership test is evaluated first. Indeed, when parentheses are used to control the order of execution these results do occur.

However, without any parentheses, the result is False. The underlying cause seems to be in a short circuit which is dependent on the inequality comparison, seen in the JUMP_IF_FALSE_OR_POP instruction.

This expression is very synthetic, but I am submitting this bug under the worry that it speaks to a more significant error in the bytecode produced for inequality tests (or membership tests).
msg362614 - (view) Author: Tim Peters (tim.peters) * (Python committer) Date: 2020-02-25 03:21
"!=" and "in" are comparison operators in Python, and _all_ comparison operators "chain".  That is,

x < y < z


x < y and y < z

(although y is evaluated only once), and in the same way

True != True in [False, False]


True != True and True in [False, False]
msg362615 - (view) Author: Orion Fisher (Orion Fisher) Date: 2020-02-25 03:36
Ah, I see, thank you for the clear explanation.

Chaining is so intuitive in the case it is always introduced with, yet I never knew it applied so generally.

(New to the interface so I hope this is indeed where I must reply.)
msg362616 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2020-02-25 03:40
For reference see the section on comparisons in the language reference:
msg362622 - (view) Author: Tim Peters (tim.peters) * (Python committer) Date: 2020-02-25 03:53
Orion, you're using the interface as intended :-)

While it's too late to change now, if Python started over from scratch I'd argue to leave "in" and "not in" out of this feature - chaining them is _usually_ an unintended behavior.

Then again, sometimes it is slightly useful.  For example, if I want to know if `n` is in a set of primes, but isn't even,

if 2 != n in some_set_of_primes:

does the job succinctly.  But not really "Pythonically", since even experienced Python programmers may scratch their heads when reading it :-(
Date User Action Args
2020-02-25 03:53:43tim.peterssetmessages: + msg362622
2020-02-25 03:40:05eryksunsetresolution: not a bug

messages: + msg362616
nosy: + eryksun
2020-02-25 03:36:31Orion Fishersetmessages: + msg362615
2020-02-25 03:34:16Orion Fishersetstatus: open -> closed
stage: resolved
2020-02-25 03:21:20tim.peterssetnosy: + tim.peters
messages: + msg362614
2020-02-25 03:08:43Orion Fishercreate