We will use the dis module to analyze bytecode.
import dis dis.dis("'1' in '111' == True")
We get the following conclusion
1 0 LOAD_CONST 0 ('1') 2 LOAD_CONST 1 ('111') 4 DUP_TOP 6 ROT_THREE 8 COMPARE_OP 6 (in) 10 JUMP_IF_FALSE_OR_POP 18 12 LOAD_CONST 2 (True) 14 COMPARE_OP 2 (==) 16 RETURN_VALUE >> 18 ROT_TWO 20 POP_TOP 22 RETURN_VALUE
The LOAD_CONST instruction loads constants on the stack, DUP_TOP duplicates the value of the top of the stack and adds it to the stack, ROT_THREE raises 2 and 3 values in the stack 1 position up, dropping the value of the top of the stack to position 3. Thus, before the in operation (offset 8) in the stack values are stored ['111', '1', '111']. Further, there are two possible scenarios:
In the case of obtaining a false value, go to offset 18 with the stack [False, '111'], ROT_TWO swaps the top two values of the stack, we get the stack ['111', False]. POP_TOP will remove '111' and RETURN_VALUE will return False.
If a true value is obtained after executing LOAD_CONST at offset 12, the stack will contain the following values [True, '111']. Next, the operation compares the values of True and '111', the result of which is pushed onto the stack and then returned.
It turns out that the result of executing the expression '1' in '111' == True will be equal to the result of executing '1' in '111' and '111' == True