tags:

views:

59

answers:

3

How does Python (2.6.4, specifically) determine list membership in general? I've run some tests to see what it does:

def main():
    obj = fancy_obj(arg='C:\\')
    needle = (50, obj)
    haystack = [(50, fancy_obj(arg='C:\\')), (1, obj,), needle]

    print (1, fancy_obj(arg='C:\\'),) in haystack
    print needle in haystack

if __name__ == '__main__':
    main()

Which yields:

False
True

This tells me that Python is probably checking the object references, which makes sense. Is there something more definitive I can look at?

+3  A: 

From (An Unofficial) Python Reference Wiki:

For the list and tuple types, x in y is true if and only if there exists an index i such that x == y[i] is true.

So in your example, if the fancy_obj class stored the value of arg in an instance variable and were to implement an __eq__ method that returned True if the two fancy_objs being compared had the same value for arg then (1, fancy_obj(arg='C:\\'),) in haystack would be True.

The relevant page of the Standard Library reference is: Built-in Types, specifically 5.6 Sequence Types

mikej
+1  A: 

Python is using the (equivalent of) the == operator. If the fancy_obj class does not define __eq__ (or the crufty old __cmp__, still supported for backwards compatibility) then equality, ==, "falls back" to identity, is, and that appears to be what's happening here.

The relevant docs are here, and I quote:

x in s True if an item of s is equal to x, else False

and "equal to" means == is true.

Alex Martelli
+3  A: 

Here is code from the Python SVN:

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;
}

so basically it uses the == with the object and each object in the list.

Justin Peel