How Is The __contains__ Method Of The List Class In Python Implemented?
Solution 1:
No, they're not equivalent. For example:
>>>mode = float('nan')>>>allowed_modes = [mode]>>>any(mode == allowed_mode for allowed_mode in allowed_modes)
False
>>>mode in allowed_modes
True
See Membership test operations for more details, including this statement:
For container types such as list, tuple, set, frozenset, dict, or collections.deque, the expression
x in y
is equivalent toany(x is e or x == e for e in y)
.
Solution 2:
Python lists are defined in C code.
You may verify it by looking at the code in the repository:
staticintlist_contains(PyListObject *a, PyObject *el){
Py_ssize_t i;
int cmp;
for (i = 0, cmp = 0 ; cmp == 0 && i < Py_SIZE(a); ++i)
cmp = PyObject_RichCompareBool(el, PyList_GET_ITEM(a, i),
Py_EQ);
return cmp;
}
It's fairly straight forward to see that this code loops over items in list and stop when first equality (Py_EQ
) comparison between el
and PyList_GET_ITEM(a, i)
returns 1.
Solution 3:
Not equivalent since the any requires an extra function call, a generator expression and things.
>>>mode = "access">>>allowed_modes =["access", "read", "write"]>>>>>>deff1():... mode in allowed_modes...>>>deff2():...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
>>>
Post a Comment for "How Is The __contains__ Method Of The List Class In Python Implemented?"