Not equivalent since the any requires an extra function call, a generator expression and things.
>>> mode = "access"
>>> allowed_modes =["access", "read", "write"]
>>>
>>> def f1():
... mode in allowed_modes
...
>>> def f2():
... any(mode == x for x in allowed_modes)
...
>>>
>>>
>>> import dis
>>> dis.dis
dis.dis( dis.disassemble( dis.disco( dis.distb(
>>> dis.dis(f1)
2 0 LOAD_GLOBAL 0 (mode)
3 LOAD_GLOBAL 1 (allowed_modes)
6 COMPARE_OP 6 (in)
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
>>> dis.dis(f2)
2 0 LOAD_GLOBAL 0 (any)
3 LOAD_CONST 1 (<code object <genexpr> at 0x7fb24a957540, file "<stdin>", line 2>)
6 LOAD_CONST 2 ('f2.<locals>.<genexpr>')
9 MAKE_FUNCTION 0
12 LOAD_GLOBAL 1 (allowed_modes)
15 GET_ITER
16 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
19 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
22 POP_TOP
23 LOAD_CONST 0 (None)
26 RETURN_VALUE
>>>
This is more instructive than the python source for the methods themselves but here is the source of __contains__
for lists and the loop is in C which will probably be faster than a Python loop.
Some timing numbers confirm this.
>>> import timeit
>>> timeit.timeit(f1)
0.18974408798385412
>>> timeit.timeit(f2)
0.7702703149989247
>>>