我有一些python代码抛出KeyError异常。到目前为止,我还没有能够在操作环境之外重现,所以我不能在这里发布一个简化的测试用例。
引发异常的代码正在迭代这样的循环:
for k in d.keys():
if condition:
del d[k]
del[k]
行抛出异常。我在其周围添加了try/except
子句,并且能够确定k in d
为False,但k in d.keys()
为True。
d
的键是旧式类实例的绑定方法。
该类实现__cmp__
和__hash__
,这就是我一直关注的地方。
答案 0 :(得分:18)
k in d.keys()
将针对每个密钥迭代地测试相等性,而k in d
使用__hash__
,因此您的__hash__
可能会被破坏(即它会为比较相等的对象返回不同的哈希值)。
答案 1 :(得分:5)
感兴趣的简单例子:
>>> count = 0
>>> class BrokenHash(object):
... def __hash__(self):
... global count
... count += 1
... return count
...
... def __eq__(self, other):
... return True
...
>>> foo = BrokenHash()
>>> bar = BrokenHash()
>>> foo is bar
False
>>> foo == bar
True
>>> baz = {bar:1}
>>> foo in baz
False
>>> foo in baz.keys()
True
答案 2 :(得分:4)
在迭代它时不要删除d
中的项目,将要删除的键存储在列表中并在另一个循环中删除它们:
deleted = []
for k in d.keys():
if condition:
deleted.append(k)
for k in deleted:
del d[k]
答案 3 :(得分:-1)
您正在做的事情会在Java中引发并发修改异常。 d.keys()
会在您调用密钥时创建一个密钥列表,但该列表现在是静态的 - 对d
的修改不会更改d.keys()
的存储版本。因此,当您迭代d.keys()
但删除项目时,您最终可能会修改不再存在的密钥。
您可以使用d.pop(k, None)
,如果k
不存在,则会返回映射到None
或k
的值。这可以避免KeyError
问题。
编辑:为了澄清,为了防止更多的幻影downmods(没有负面反馈的问题,只需使其具有建设性并留下评论,以便我们可以进行可能提供信息的讨论 - 我在这里学习以及帮助):< / p>
确实,在这种特殊情况下,它不应该搞砸。我只是把它作为一个潜在的问题,因为如果他在程序的另一部分中使用相同类型的编码方案,那么他不那么小心/幸运他如何处理数据结构,这样的问题可能会出现。他甚至不使用字典,而是实现某些方法的类,因此您可以以类似的方式对待它。