The trick to the output you're getting is that and
and or
in Python always evaluate to one of their operands -- generally the one that had to be evaluated last to determine the truthiness of the operation:
1 or 2 # returns 1 because since 1 is true, there's no need to evaluate the second argument.
1 or 0 # returns 1, same thing.
0 or 2 # returns 2 because 0 is false, so we need to evaluate the second arg to check whether the operation is true.
0 or "" # returns "" (both 0 and "" are false).
1 and 2 # returns 2 because for an and operation to be true, both its operands need to be checked for truthiness.
0 and 2 # returns 0, because we know that if the first operand is false, so is the whole operation.
0 and None # Still returns 0, we don't even need to check the second operand.
So when you're evaluating (1 or 2) in [1, 3, 5]
(where in truth you want 1 in [1, 3, 5] or 2 in [1, 3, 5]
), what really happens is (1 or 2)
is evaluated to 1
, and your operation becomes 1 in [1, 3, 5]
.