Skip to content Skip to sidebar Skip to footer

How Is The __contains__ Method Of The List Class In Python Implemented?

Suppose I define the following variables: mode = 'access' allowed_modes = ['access', 'read', 'write'] I currently have a type checking statement which is assert any(mode == allowe

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 to any(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?"