Python (and me) getting confused finding keys

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Tue Dec 22 17:48:22 EST 2009


On Tue, 22 Dec 2009 17:33:04 +0100, John wrote:

> Hi there,
> 
> I have a rather lengthy program that troubles me for quite some time.
> After some debugging, I arrived at the following assertion error:
> 
> for e in edges.keys():
> 	assert edges.has_key(e)
> 
> Oops!? Is there ANY way that something like this can possibly happen?

In another post, you assert that:

(1) You aren't knowingly using threads, so it's not likely that another 
thread is modifying edges.

(2) edges is a regular dictionary, not a custom mapping class.


In that case, I would say that the most likely culprit is that the edges 
are mutable but given a hash function. I can reproduce the problem like 
this:


>>> class Edge:
...     def __init__(self, start, finish):
...             self.ends = (start, finish)
...     def __eq__(self, other):
...             return self.ends == other.ends
...     def __hash__(self):
...             return hash(self.ends)
...
>>> edges = {Edge(1, 5): None}
>>> for e in edges:
...     assert e in edges  # same as edges.has_key(e)
...     e.ends = (5, 6)
...     assert e in edges, "and now it's gone"
...
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
AssertionError: and now it's gone



So the likely problem is that your edge type is mutable and being mutated.

Now, if your code snippet above:

for e in edges.keys():
    assert edges.has_key(e)


is a literal copy-and-paste from the failing code, I can only assume that 
the edge type __eq__ or __hash__ method mutates self.

The lesson of this? Do not make mutable classes hashable.

The obvious follow-up is to ask how to make an immutable class.

http://northernplanets.blogspot.com/2007/01/immutable-instances-in-python.html



-- 
Steven



More information about the Python-list mailing list