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