“k in d”怎么可能是假的,但是“d.keys()中的k”是真的吗?

时间:2010-10-27 17:50:11

标签: python dictionary python-2.x

我有一些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__,这就是我一直关注的地方。

4 个答案:

答案 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不存在,则会返回映射到Nonek的值。这可以避免KeyError问题。

编辑:为了澄清,为了防止更多的幻影downmods(没有负面反馈的问题,只需使其具有建设性并留下评论,以便我们可以进行可能提供信息的讨论 - 我在这里学习以及帮助):< / p>

确实,在这种特殊情况下,它不应该搞砸。我只是把它作为一个潜在的问题,因为如果他在程序的另一部分中使用相同类型的编码方案,那么他那么小心/幸运他如何处理数据结构,这样的问题可能会出现。他甚至不使用字典,而是实现某些方法的类,因此您可以以类似的方式对待它。