哈希值相同时仍抛出KeyError的问题排查
根据你提供的代码和运行结果,虽然目标对象与字典中的键地址相同、哈希值一致,但in判断返回False并抛出KeyError,核心原因在于字典查找依赖哈希值定位桶,再通过__eq__方法匹配键,二者任一环节出问题都会导致查找失败。具体可能的原因及解决方案如下:
可能的原因
1. 自定义属性的__eq__方法实现错误
你的TransactionDesignation类的__eq__方法依赖id、child_of、gd三个属性的相等性判断。如果这三个属性中任意一个是自定义类型,且其__eq__方法实现错误(比如错误地返回False,或未正确比较实例属性),会导致即使是同一个TransactionDesignation实例,__eq__也会返回False,字典无法匹配到键。
比如,假设id是一个自定义ORM模型实例,其__eq__方法错误地比较数据库主键(而该实例尚未入库,主键为None),就会出现同一个实例的id == id返回False的情况。
2. 对象属性被修改后恢复,导致字典内部结构异常
Python字典在插入键时会缓存键的哈希值。如果将对象加入字典后,修改了影响哈希值的属性(id/child_of/gd),即使之后改回原属性,字典的内部结构可能已无法正确关联当前对象与原存储位置,极端情况下会导致查找失败。
3. 未处理非同类实例的比较
你的__eq__方法未先判断other是否为TransactionDesignation实例,如果字典中存在其他类型的键,或查找时意外传入非同类对象,可能会触发错误的比较逻辑(甚至抛出异常),导致查找失败。
解决方案
1. 修复属性的相等性判断逻辑
检查id、child_of、gd的类型及其__eq__实现:
- 对于自定义类型,确保其
__eq__方法正确比较实例的核心属性; - 如果不需要自定义相等性判断,可直接使用默认的
is判断(即比较对象地址),但需注意这会改变相等性逻辑。
2. 确保字典键的不可变性
一旦将TransactionDesignation实例作为字典键,就不要修改其id、child_of、gd属性。如果必须修改,需先从字典中删除该键,修改后重新添加:
# 修改属性前先删除键 del logs[TRANSACTIONS][transaction_designation] # 修改属性 transaction_designation.id = new_id # 重新添加到字典 logs[TRANSACTIONS][transaction_designation] = transaction_value
3. 完善__eq__方法的类型判断
在__eq__方法中先判断other的类型,避免与非同类对象错误比较:
def __eq__(self, other): if not isinstance(other, TransactionDesignation): return False return self.id == other.id and self.child_of == other.child_of and self.gd == other.gd
4. 快速排查测试
添加以下测试代码,定位问题根源:
# 测试同一个实例的__eq__结果 td = TransactionDesignation(gd, id, child_of) print(td == td) # 若返回False,说明__eq__方法存在问题 # 测试属性的相等性 print(td.id == td.id) print(td.child_of == td.child_of) print(td.gd == td.gd)
内容的提问来源于stack exchange,提问作者Bortek23

