It really depends on the version of Python. In Python 2.7 , there were no constants specified in the bytecode, so in Python 2, for a fixed constant, a small set of values ββuses a tuple:
if x in ('2', '3', '5', '7'): ...
A tuple is a constant:
>>> dis.dis(lambda: item in ('1','2','3','4')) 1 0 LOAD_GLOBAL 0 (item) 3 LOAD_CONST 5 (('1', '2', '3', '4')) 6 COMPARE_OP 6 (in) 9 RETURN_VALUE
Python is also smart enough to optimize the list of constants in Python 2.7 for a tuple:
>>> dis.dis(lambda: item in ['1','2','3','4']) 1 0 LOAD_GLOBAL 0 (item) 3 LOAD_CONST 5 (('1', '2', '3', '4')) 6 COMPARE_OP 6 (in) 9 RETURN_VALUE
But Python 2.7 bytecode (and the compiler) does not support persistent set support:
>>> dis.dis(lambda: item in {'1','2','3','4'}) 1 0 LOAD_GLOBAL 0 (item) 3 LOAD_CONST 1 ('1') 6 LOAD_CONST 2 ('2') 9 LOAD_CONST 3 ('3') 12 LOAD_CONST 4 ('4') 15 BUILD_SET 4 18 COMPARE_OP 6 (in) 21 RETURN_VALUE
This means that the condition in if needs to be rebuilt for each test. .
However, in Python 3.4, bytecode supports the given constants; there the code is evaluated as follows:
>>> dis.dis(lambda: item in {'1','2','3','4'}) 1 0 LOAD_GLOBAL 0 (item) 3 LOAD_CONST 5 (frozenset({'4', '2', '1', '3'})) 6 COMPARE_OP 6 (in) 9 RETURN_VALUE
As for multi- or code, it produces completely disgusting bytecode:
>>> dis.dis(lambda: item == '1' or item == '2' or item == '3' or item == '4') 1 0 LOAD_GLOBAL 0 (item) 3 LOAD_CONST 1 ('1') 6 COMPARE_OP 2 (==) 9 JUMP_IF_TRUE_OR_POP 45 12 LOAD_GLOBAL 0 (item) 15 LOAD_CONST 2 ('2') 18 COMPARE_OP 2 (==) 21 JUMP_IF_TRUE_OR_POP 45 24 LOAD_GLOBAL 0 (item) 27 LOAD_CONST 3 ('3') 30 COMPARE_OP 2 (==) 33 JUMP_IF_TRUE_OR_POP 45 36 LOAD_GLOBAL 0 (item) 39 LOAD_CONST 4 ('4') 42 COMPARE_OP 2 (==) >> 45 RETURN_VALUE