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:
static int
list_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"]
>>>
>>> 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
>>>
Post a Comment for "How Is The __contains__ Method Of The List Class In Python Implemented?"