如何“k在d中”为假,但“k在d.keys()中”为真?

7 投票
4 回答
1707 浏览
提问于 2025-04-16 06:11

我有一些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 个回答

4

在遍历一个叫 d 的东西时,不要直接删除里面的项目。你可以先把想要删除的项目的键存到一个列表里,然后再用另一个循环去删除它们。

deleted = []
for k in d.keys():
    if condition:
        deleted.append(k)
for k in deleted:
    del d[k]
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
18

k in d.keys() 这个写法会一个一个地检查每个键,看是否和 k 相等,而 k in d 则是用 __hash__ 方法来快速判断。所以如果你的 __hash__ 方法有问题(也就是说,它对那些比较相等的对象返回了不同的哈希值),那么可能会导致错误的结果。

撰写回答