我理解可变对象can't be hashed,但为什么在可变对象的方法中也应如此,特别是考虑到它们按预期进行比较?
例如:
>>> d1, d2 = {}, {}
>>> d1.keys == d2.keys
False
>>> set([d1.keys])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
在示例中,d1.keys
本身并不是异常抱怨的dict
。简单地将dict
作为属性显然不是可以清除的一般条款,因为默认情况下,用户创建的类的实例都是可清除的并且具有__dict__
属性。方法对象本身不会以任何有意义的方式在其生命周期内发生变化,无论其__self__
组件是否可变。有没有什么方法我没有看到可变对象上的哈希方法会破坏哈希隐含的契约?
下面是我对包装器的尝试,它确保方法可以清洗,并且对常规方法对象也很好。对于通常不可用的方法,哈希值是从包含方法实现对象的元组和方法的__self__
组件的id计算的。有什么理由可能会让我感到害怕?
class HashableMethod(object):
__slots__ = ['_method', '_hashval', '__weakref__']
def __init__(self, method):
self._method = method
def __getattr__(self, name):
return getattr(self._method, name)
def __call__(self, *args, **kwds):
return self._method(*args, **kwds)
def __eq__(self, other):
return self._method == other
def __hash__(self):
try:
return self._hashval
except AttributeError: # self._hashval is not yet calculated
pass
meth = self._method
try:
hashval = self._hashval = hash(meth)
except TypeError: # self._method is not ordinarily hashable
obj = meth.__self__
try:
func = meth.__func__
except AttributeError: # self._method is builtin
func = getattr(type(obj), meth.__name__)
hashval = self._hashval = hash((func, id(obj)))
return hashval