difference between `x in list` and `list.index(x)` for instances of anew-style class

R

Riccardo Murri

Hello,

I have some code that stops when trying to find a graph in a list of
similar graphs::

(Pydb) list
110 try:
111 canonical = self.base[self.base.index(graph)]
112 except ValueError:
113 raise ValueError, \
114 "Cannot find canonical representative for graph `%s`." \
115 -> % (repr(graph),)
116
....

The list `self.base` contains "canonical" forms of the graphs and the
`graph` object must compare equal to some item of the list, which
indeed it does::

(Pydb) p graph == self.base[27]
True

(Pydb) p graph in self.base
True

However, I cannot directly get the index of the canonical graph (the
number "27" above was found by manual inspection)::

(Pydb) self.base.index(graph)
*** ValueError: list.index(x): x not in list

All graphs are instances of a `Graph` new-style class that implements
comparison operators `__eq__` and `__ne__`, but no other rich-compare
stuff.

I'm using Python 2.5::

Python 2.5 (release25-maint, Dec 9 2006, 16:17:58)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-20)] on linux2

So my question is: what are the implementation differences between `x
in list` and `list.index(x)` and why can one report that an item is in
the list while the other cannot find its index? Should I add
something to the `Graph` class so that `index` works?

Thanks for any hint!
 
B

bpgbaires

The list `self.base` contains "canonical" forms of the graphs and the
`graph` object must compare equal to some item of the list, which
indeed it does::

  (Pydb) p graph == self.base[27]  
  True

  (Pydb) p graph in self.base
  True

However, I cannot directly get the index of the canonical graph (the
number "27" above was found by manual inspection)::

  (Pydb) self.base.index(graph)
  *** ValueError: list.index(x): x not in list

All graphs are instances of a `Graph` new-style class that implements
comparison operators `__eq__` and `__ne__`, but no other rich-compare
stuff.

I'm using Python 2.5::

  Python 2.5 (release25-maint, Dec  9 2006, 16:17:58)
  [GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-20)] on linux2

So my question is: what are the implementation differences between `x
in list` and `list.index(x)` and why can one report that an item is in
the list while the other cannot find its index?  Should I add
something to the `Graph` class so that `index` works?

(I've checked on 2.5.1 but I don't see any relevant differences with
the 2.5 version). Looking at the source for both methods, they only
use the __eq__ operator, but there is a slight difference: while one
evaluates list==x, the other reverses the operands. If your __eq__
is not reflexive, that could explain the difference.

class Graph(object):
def __init__(self, *items):
self.items = items

def __eq__(self, other):
if len(self.items)>len(other.items): return False
return self.items == other.items[:len(self.items)]

py> List = [Graph(1,2,3), Graph(4,5,6), Graph(1,2,3,4)]
py> g = Graph(1,2)
py> g in List
True
py> List.index(g)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: list.index(x): x not in list
py> List[0]==g
False
py> g==List[0]
True

In your example, see if self.base[27]==graph is still True.
 
R

Riccardo Murri

The list `self.base` contains "canonical" forms of the graphs and the
`graph` object must compare equal to some item of the list, which
indeed it does::

  (Pydb) p graph == self.base[27]  
  True

  (Pydb) p graph in self.base
  True

However, I cannot directly get the index of the canonical graph (the
number "27" above was found by manual inspection)::

  (Pydb) self.base.index(graph)
  *** ValueError: list.index(x): x not in list

All graphs are instances of a `Graph` new-style class that implements
comparison operators `__eq__` and `__ne__`, but no other rich-compare
stuff.

I'm using Python 2.5::

  Python 2.5 (release25-maint, Dec  9 2006, 16:17:58)
  [GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-20)] on linux2

So my question is: what are the implementation differences between `x
in list` and `list.index(x)` and why can one report that an item is in
the list while the other cannot find its index?  Should I add
something to the `Graph` class so that `index` works?

(I've checked on 2.5.1 but I don't see any relevant differences with
the 2.5 version). Looking at the source for both methods, they only
use the __eq__ operator, but there is a slight difference: while one
evaluates list==x, the other reverses the operands. If your __eq__
is not reflexive, that could explain the difference.


That was indeed the reason: a bug in Graph.__eq__ broke reflexivity in
certain cases.

Thank you very much!!
 
G

Gabriel Genellina

  (Pydb) p graph == self.base[27]  
  True
  (Pydb) p graph in self.base
  True
  (Pydb) self.base.index(graph)
  *** ValueError: list.index(x): x not in list
Looking at the source for both methods, they only
use the __eq__ operator, but there is a slight difference: while one
evaluates list==x, the other reverses the operands. If your __eq__
is not reflexive, that could explain the difference.


That was indeed the reason: a bug in Graph.__eq__ broke reflexivity in
certain cases.


Combined with some other WTF bugs I've found at work, lately I feel
more like a detective than a software developer :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,149
Members
46,695
Latest member
StanleyDri

Latest Threads

Top