Python的dict将类型作为键时__hash__与__eq__的运作机制是怎样的?
核心原理解答
首先你要明确一个Python的基础规则:所有自定义类本身,就是type类的实例。你遇到的疑惑本质是混淆了「类给自身实例提供的方法」和「类作为其他类的实例时调用的方法」。
测试代码报错的原因
你写Apple.__hash__()的时候,调用的是Apple类继承自object、给Apple的实例(比如an_apple)用的__hash__方法,这个方法要求第一个参数必须是Apple的实例,你不传当然会报错。但这根本不是字典把Apple作为键时会调用的方法。
dict处理键的统一逻辑
不管键是什么对象,dict计算哈希和做相等校验的逻辑都是固定的:
- 计算哈希时,执行
hash(键对象),本质等价于调用type(键对象).__hash__(键对象) - 相等校验时,执行
键对象1 == 键对象2,本质等价于调用type(键对象1).__eq__(键对象1, 键对象2)
当你把Apple类作为键时:
- 键对象就是
Apple,它的类型是type,所以实际调用的是type.__hash__(Apple) - 相等校验时调用的是
type.__eq__(Apple, 待比较的对象)
type类本身已经实现了符合要求的__hash__和__eq__方法,所有类作为type的实例天然是可哈希的,完全满足dict键的要求,所以可以正常作为键使用。
验证示例
你可以执行以下代码验证上述逻辑:
# 不会报错,正常返回Apple类的哈希值 print(hash(Apple)) # 输出True,相等校验正常 print(Apple == type(an_apple))
这就是你的lookup字典可以正常工作的原因:type(an_apple)得到的就是Apple类对象,和字典里存的键哈希值一致、相等判断为真,自然可以取出对应的lambda执行。
内容的提问来源于stack exchange,提问作者Stephen Carboni
相关产品推荐
相关产品推荐

