変更可能なオブジェクトをハッシュできないことは理解していますが、特に期待どおりに比較できることを考えると、変更可能なオブジェクトのメソッドにもこれが当てはまるのはなぜですか?
例えば:
>>> 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
ユーザーが作成したクラスのインスタンスは、デフォルトでハッシュ可能であり、属性を持っているため、単純に属性として a を持つことは、明らかにハッシュ可能であることの一般的な障害にはなりません__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