如何控制Python类方法的哈希值?及3.7与3.8版本差异疑问
控制Python类方法哈希值的问题解答
1. 3.7以上版本实现方法哈希相等的方案
要让不同实例的同名绑定方法哈希值相等,核心是让哈希计算逻辑仅依赖底层函数而非实例对象。可以通过拦截实例的属性获取过程,返回自定义的绑定方法对象来实现:
class BoundMethod: def __init__(self, instance, func): self.instance = instance self.func = func def __call__(self, *args, **kwargs): # 保留原方法的调用逻辑 return self.func(self.instance, *args, **kwargs) def __hash__(self): # 哈希仅基于底层函数对象 return hash(self.func) class A: def hello(self, arg): print(arg) def __hash__(self): return 12345 def __getattribute__(self, name): attr = super().__getattribute__(name) # 判断是否为实例的绑定方法(排除类方法、静态方法) if callable(attr) and hasattr(attr, '__func__'): return BoundMethod(self, attr.__func__) return attr # 测试验证 a = A() b = A() print(hash(a.hello) == hash(b.hello)) # 输出 True
也可以用更轻量的方式,直接给动态创建的绑定方法替换__hash__逻辑:
class A: def hello(self, arg): print(arg) def __hash__(self): return 12345 a = A() b = A() # 手动替换绑定方法的哈希计算逻辑 a.hello.__hash__ = lambda: hash(a.hello.__func__) b.hello.__hash__ = lambda: hash(b.hello.__func__) print(hash(a.hello) == hash(b.hello)) # 输出 True
2. 版本间哈希结果变化的原因
Python 3.8对**绑定方法(bound method)**的哈希计算逻辑做了关键修改:
- 在3.7及更早版本中,绑定方法的哈希值由「底层函数对象的哈希」与「实例对象的哈希」异或得到(即
hash(method) = hash(method.__func__) ^ hash(method.__self__))。你的代码中A类重写了__hash__返回固定值12345,不同实例的同名方法会因为hash(method.__self__)相同,最终异或结果一致。 - 从3.8开始,绑定方法不再使用自定义哈希逻辑,转而采用默认的
object.__hash__实现——基于对象的内存地址(id)计算哈希。每个绑定方法都是独立的对象实例,因此不同实例的同名方法哈希值必然不同。
内容的提问来源于stack exchange,提问作者meow
相关产品推荐
相关产品推荐

