web-dev-qa-db-ja.com

なぜPythonはハッシュ可能に設定しますか?

Pythonでpowerset関数を実装する方法を詳しく説明したブログ投稿を見つけました。だから私はそれを自分のやり方で試してみましたが、Pythonは明らかにセットのセットを持つことはできません。セットはハッシュ可能ではないからです。セットのセットであり、実際のセット操作を使用して実装したいと考えました。

>>> set([ set() ])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'

正当な理由はありますかPythonセットがハッシュ可能ではありませんか?

58
Dan Burton

一般に、Pythonでは不変オブジェクトのみがハッシュ可能です。 set()-frozenset()-の不変のバリアントはハッシュ可能です。

103
Sven Marnach

可変だからです。

それらがハッシュ可能である場合、ハッシュは静かに「無効」になる可能性があり、それはほとんどハッシュを無意味にします。

27
phihag

Python docs:

ハッシュ可能
オブジェクトは、その存続期間中に変更されないハッシュ値(hash()メソッドが必要)を持ち、他のオブジェクトと比較できる場合、ハッシュ可能です。 (eq()またはcmp()メソッドが必要です)。等しいと比較するハッシュ可能なオブジェクトは、同じハッシュ値を持たなければなりません。

これらのデータ構造は内部的にハッシュ値を使用するため、ハッシュ可能性により、オブジェクトは辞書キーおよびセットメンバーとして使用可能になります。

Pythonの不変の組み込みオブジェクトはすべてハッシュ可能ですが、可変コンテナ(リストや辞書など)はありません。ユーザー定義クラスのインスタンスであるオブジェクトは、デフォルトでハッシュ可能です。それらはすべて等しくないものであり、ハッシュ値はid()です。

16
John Gaines Jr.

これが役立つ場合...何らかの理由でハッシュ化できないものをハッシュ化可能なものに本当に変換する必要がある場合は、次のようにすることができます:

from collections import Hashable, MutableSet, MutableSequence, MutableMapping

def make_hashdict(value):
    """
    Inspired by https://stackoverflow.com/questions/1151658/python-hashable-dicts
     - with the added bonus that it inherits from the dict type of value
       so OrderedDict's maintain their order and other subclasses of dict() maintain their attributes
    """
    map_type = type(value)

    class HashableDict(map_type):
        def __init__(self, *args, **kwargs):
            super(HashableDict, self).__init__(*args, **kwargs)
        def __hash__(self):
            return hash(Tuple(sorted(self.items())))

    hashDict = HashableDict(value)

    return hashDict


def make_hashable(value):
    if not isinstance(value, Hashable):
        if isinstance(value, MutableSet):
            value = frozenset(value)
        Elif isinstance(value, MutableSequence):
            value = Tuple(value)
        Elif isinstance(value, MutableMapping):
            value = make_hashdict(value)

        return value

my_set = set()
my_set.add(make_hashable(['a', 'list']))
my_set.add(make_hashable({'a': 1, 'dict': 2}))
my_set.add(make_hashable({'a', 'new', 'set'}))

print my_set

私のHashableDict実装は、 here からの最も単純で最も厳密ではない例です。酸洗などをサポートするより高度なHashableDictが必要な場合は、他の多くの実装を確認してください。上記の私のバージョンでは、元のdictクラスを保持したいので、OrderedDictsの順序を保持しました。また、属性のようなアクセスには here のAttrDictを使用します。

上記の私の例は決して権威あるものではなく、セットにいくつかのものを保存する必要があり、それらを最初に「ハッシュ化」する必要がある同様の問題に対する私のソリューションです。

6
flutefreak7