Pythonで「ハッシュ可能」とはどういう意味ですか?


193

インターネットで検索してみましたが、ハッシュ可能という意味が見つかりませんでした。

彼らがオブジェクトと言うとき、hashableまたはhashable objectsそれはどういう意味ですか?


1
ハッシュ可能__hash__()メソッドのドキュメントを参照してください。
ʇsәɹoɈ

5
ハッシュ可能オブジェクトまたは何かを検索しますが、ハッシュの実際の意味を説明するリンクはありません
user1755071

回答:


181

Python用語集から:

オブジェクトは、その存続期間中に決して変更されない(__hash__()メソッドが必要)ハッシュ値があり、他のオブジェクトと比較できる(__eq__()または__cmp__()メソッドが必要)場合、ハッシュ可能です。等しいと比較するハッシュ可能なオブジェクトは、同じハッシュ値を持つ必要があります。

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

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


2
hash valueハッシュ値が今ある場合。あなたは、いくつかの例を与えることができます
user1755071

2
@ user55711:ここで、ハッシュ値はを呼び出した結果です__hash__()。より一般的には、en.wikipedia.org / wiki / Hash_functionを
NPE

16
@TorstenBronger:2つの等しくないオブジェクトが同じ値にハッシュできるため。つまり、ハッシュは不可逆です。
NPE

1
python-2.7.12では、の結果はの結果のid(object)16倍ですobject.__hash__()。そのため、このバージョンの用語集の抜粋は正しくありません。ハッシュ値はではありませんがid()、そこから派生しています(Python 2.7.12の更新されたドキュメントに実際に記載されています)。
davidA 2016年

2
私はこれが古い投稿であることを知っていますが、ここにコピーされた用語集のエントリが完全に正しいわけではないことを言及する価値があります。変更可能なオブジェクト(リストなど)をタプル内に配置できます。タプルはまだ不変ですが、その内部のリストを変更できるため、ハッシュ化できません。hash((1, [2, 3]))実際に見てみてください。用語集のエントリをハッシュ可能に修正するリクエストを投稿しました。
John Riehl

102

ここでのすべての回答には、Pythonでのハッシュ可能なオブジェクトの実用的な説明がありますが、最初にハッシュという用語を理解する必要があると思います。

ハッシュとは、大量のデータを格納してすばやくアクセスする高性能の擬似ランダムアクセスデータ構造を作成するために使用されるコンピュータサイエンスの概念です。

たとえば、電話番号が10,000あり、それらを配列(連続したメモリロケーションにデータを格納し、ランダムアクセスを提供するシーケンシャルデータ構造)に格納したいが、必要な量の連続していない場合があります。メモリの場所。

したがって、代わりにサイズ100の配列を使用し、ハッシュ関数を使用して値のセットを同じインデックスにマップできます。これらの値はリンクリストに格納できます。これにより、アレイと同様のパフォーマンスが得られます。

これで、ハッシュ関数は、配列のサイズで数を割り、残りをインデックスとして取るのと同じくらい簡単になります。

詳細については、https://en.wikipedia.org/wiki/Hash_functionを参照してください

ここに別の良いリファレンスがあります:http : //interactivepython.org/runestone/static/pythonds/SortSearch/Hashing.html


1
これはハッシュに関する興味深い見方です。私はそのようには考えていません。
yuvgin

@yuvginハッシュテーブルは、スパース配列を実装するためによく使用されます(つまり、ここに示す例)。
Eli Korvigo 2019年

@EliKorvigo通常の配列は、ハッシュテーブルの非常に最適化されたバージョンと考えるのが好きです。
Mark Ransom

1
ハッシュの概念を明確にするために、電話番号配列のシナリオに関する簡単なコードを作成できますか?
Istiaque Ahmed

18

変更可能でないもの(変更可能であること、変更される可能性が高いこと)はハッシュ化できます。検索するハッシュ関数に加えて、クラスにハッシュ関数がある場合は、たとえば、dir(tuple)そして__hash__メソッドを探して、ここにいくつかの例があります

#x = hash(set([1,2])) #set unhashable
x = hash(frozenset([1,2])) #hashable
#x = hash(([1,2], [2,3])) #tuple of mutable objects, unhashable
x = hash((1,2,3)) #tuple of immutable objects, hashable
#x = hash()
#x = hash({1,2}) #list of mutable objects, unhashable
#x = hash([1,2,3]) #list of immutable objects, unhashable

不変タイプのリスト:

int, float, decimal, complex, bool, string, tuple, range, frozenset, bytes

変更可能なタイプのリスト:

list, dict, set, bytearray, user-defined classes

私は最近、Ellipsisも不変タイプであり、のキーとして使用できることを発見しましたdict
ガーボルFekete

ユーザー定義のクラスも使用できますが、インスタンスの名前ではなくクラスの名前のみを使用できます。例えば:hash(MyClass)
ガーボルFekete

1
ユーザー定義クラスの@GáborFeketeインスタンスは、それらのクラスが__hash__およびを実装している場合、ハッシュ可能__eq__です。さらに、すべてのユーザー定義クラスは、これらのメソッドを実装している(したがってハッシュ可能である)。これは、object(ユニバーサルベースクラス)からメソッドを継承しているためです。
Eli Korvigo 2019年

6

Python用語集によると私の理解では、ハッシュ可能なオブジェクトのインスタンスを作成すると、変更不可能な値もインスタンスのメンバーまたは値に従って計算されます。たとえば、その値は次のようにdictのキーとして使用できます。

>>> tuple_a = (1,2,3)
>>> tuple_a.__hash__()
2528502973977326415
>>> tuple_b = (2,3,4)
>>> tuple_b.__hash__()
3789705017596477050
>>> tuple_c = (1,2,3)
>>> tuple_c.__hash__()
2528502973977326415
>>> id(a) == id(c)  # a and c same object?
False
>>> a.__hash__() == c.__hash__()  # a and c same value?
True
>>> dict_a = {}
>>> dict_a[tuple_a] = 'hiahia'
>>> dict_a[tuple_c]
'hiahia'

同じメンバーを持つため、tuple_aとtuple_cのハッシュ値は同じであることがわかります。dict_aのキーとしてtuple_aを使用すると、dict_a [tuple_c]の値が同じであることがわかります。つまり、dictのキーとして使用された場合、ハッシュ値は同じであるため、同じ値を返します。同じ。ハッシュ可能ではないオブジェクトの場合、メソッドハッシュはNoneとして定義されます。

>>> type(dict.__hash__) 
<class 'NoneType'>

このハッシュ値は動的な方法ではなくインスタンスの初期化時に計算されると思います。そのため、不変オブジェクトのみがハッシュ可能です。お役に立てれば。


4

Pythonのハッシュ可能オブジェクトを理解するための実用的な例を紹介しましょう。この例では2つのタプルを使用しています。タプルの各値には、その有効期間中に決して変更されない一意のハッシュ値があります。したがって、これには価値があります。2つのタプル間の比較が行われます。Id()を使用して、タプル要素のハッシュ値を取得できます。

2タプルの比較2タプル間の同等性


26
これは画像よりもテキストの方が便利です
baxx

6
それは間違った答えです。id()は、メモリ内の参照されているアドレスを表示します。これはハッシュ値ではありません。ハッシュを取得するには、__ hash __()関数を使用します。例:t1 .__ hash __()
Vlad

@ascentman間違っていると思われる回答を遠慮なく編集してください。あなたの編集はピアレビューされ、受け入れられた場合、あなたはそれに対して小さなスコアの報酬を得る。
XavierStuvw 2017年

4

Pythonでは、インデックスを返すためにオブジェクトをセットのメンバーにすることができます。つまり、一意のID / IDを持っています。

たとえば、Python 3.3では:

データ構造リストはハッシュ可能ではありませんが、データ構造タプルはハッシュ可能です。


ハッシュはid、メモリ内のオブジェクトの(ほぼ)アドレスであるとは異なります。
poolie 2016

3

Hashable =ハッシュ可能。

さて、ハッシュとは何ですか?ハッシュ関数は、オブジェクト、たとえば「Python」などの文字列を受け取り、固定サイズのコードを返す関数です。簡単にするために、戻り値は整数であると想定します。

Python 3でhash( 'Python')を実行すると、結果として5952713340227947791が返されます。異なるバージョンのPythonは、基礎となるハッシュ関数を自由に変更できるため、異なる値を取得する可能性があります。重要なことは、hash( 'Python')を何度も実行しても、同じバージョンのPythonで常に同じ結果が得られることです。

しかし、hash( 'Java')は1753925553814008565を返します。つまり、ハッシュしているオブジェクトが変化すると、結果も変化します。一方、ハッシュしているオブジェクトが変更されない場合、結果は同じままです。

なぜこれが問題なのですか?

たとえば、Python辞書では、キーが不変である必要があります。つまり、キーは変更されないオブジェクトでなければなりません。文字列は、他の基本的な型(int、float、bool)と同様に、Pythonでは不変です。タプルとfrozensetも不変です。一方、リストは変更できるため、不変ではありません(つまり、リストは変更可能です)。同様に、dictは変更可能です。

つまり、ハッシュ可能とは、不変であることを意味します。可変型をhash()関数に渡そうとすると失敗します。

>>> hash('Python')
1687380313081734297
>>> hash('Java')
1753925553814008565
>>>
>>> hash([1, 2])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash({1, 2})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
>>> hash({1 : 2})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>>
>>> hash(frozenset({1, 2}))
-1834016341293975159
>>> hash((1, 2))
3713081631934410656

1
Pythonは、各プロセスの開始時にハッシュアルゴリズムをランダムにシードすることに注意してください。したがって、異なるプロセスでhash( 'Python')を2回実行すると、実際には異なるハッシュ値が取得されます。
Dハドソン

2

Pythonでは、不変オブジェクト(整数、ブール値、文字列、タプルなど)はハッシュ可能です。つまり、その値は存続期間中は変更されません。これにより、Pythonは一意のハッシュ値を作成してそれを識別できます。これを使用して、一意のキーを追跡するための辞書や、一意の値を追跡するためのセットを使用できます。

Pythonが辞書のキーに不変のデータ型を使用する必要があるのはこのためです。


-1

ハッシュテーブルを最初から作成するには、すべての値を「なし」に設定し、要件が発生したときに変更する必要があります。ハッシュ可能なオブジェクトは、変更可能なデータ型(辞書、リストなど)を指します。一方、セットは一度割り当てられると再初期化できないため、ハッシュ化できません。一方、set()のバリアントであるfrozenset()はハッシュ可能です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.