Question

Much to my own frustration, I managed to make a list of objects in python such that the following fails:

if foo in lst:
    lst.index(foo) # ValueError: <foo> is not in list

I assure you, no trickery here:

  1. foo is an object with a custom __hash__ and __eq__, and is not being modified elsewhere
  2. both functions are idempotent and do not modify state
  3. lst is a standard python [] with no curses
Was it helpful?

Solution

The only difference between obj in listobject (or listobject.__contains__(obj)) and listobject.index() is that comparison is inverted.

list_contains does:

for (i = 0, cmp = 0 ; cmp == 0 && i < Py_SIZE(a); ++i)
    cmp = PyObject_RichCompareBool(el, PyList_GET_ITEM(a, i),
                                       Py_EQ);

while listindex does;

for (i = start; i < stop && i < Py_SIZE(self); i++) {
    int cmp = PyObject_RichCompareBool(self->ob_item[i], v, Py_EQ);

where el and v are the looked-for object, and PyList_GET_ITEM(a, i) and self->ob_item[i] are the objects contained in the list.

So lst.index() throws a ValueError exception because all of the other.__eq__(foo) calls return False and foo.__eq__(other) is never consulted. foo in lst works because foo.__eq__(other) does return True for at least one value.

You haven't given us a sample list and __eq__ implementation to verify why __eq__ returns False for all other.__eq__(foo) calls.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top