我知道可变对象不能被散列,但为什么可变对象上的方法也是如此,特别是考虑到它们按预期进行比较?
例如:
>>> 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
简单地将 adict
作为属性显然不是可散列的一般障碍,因为默认情况下,用户创建的类的实例既可散列又具有__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