web-dev-qa-db-ja.com

組み込みのpython hash()関数

Windows XP、Python 2.5:

hash('http://stackoverflow.com') Result: 1934711907

Google App Engine( http://Shell.appspot.com/ ):

hash('http://stackoverflow.com') Result: -5768830964305142685

何故ですか?異なるプラットフォーム(Windows、Linux、Mac)で同じ結果が得られるハッシュ関数を使用するにはどうすればよいですか?

80
sm1

hashlib as hash()を使用します 使用するように設計されました

辞書検索中に辞書キーをすばやく比較する

したがって、Python実装間で同じであることを保証しません。

55
SilentGhost

ドキュメントに記載されているように、組み込みhash()関数は、結果のハッシュを外部のどこかに格納するために設計されたnotです。オブジェクトのハッシュ値を提供したり、辞書に保存したりするために使用されます。また、実装固有です(GAEはPythonの修正バージョンを使用します)。チェックアウト:

>>> class Foo:
...     pass
... 
>>> a = Foo()
>>> b = Foo()
>>> hash(a), hash(b)
(-1210747828, -1210747892)

ご覧のとおり、hash()はオブジェクトの__hash__ SHAなどの「通常の」ハッシュアルゴリズムの代わりのメソッド。

上記を考えると、合理的な選択は hashlib モジュールを使用することです。

88
Mike Hordecki

応答はまったく驚きではありません:実際には

_In [1]: -5768830964305142685L & 0xffffffff
Out[1]: 1934711907L
_

信頼できる応答を取得したい場合on ASCII文字列、下位32ビットをuintとして取得します。文字列のハッシュ関数は32です。ビットセーフでalmostポータブル。

反対に、___hash___メソッドを不変に明示的に定義していないオブジェクトのhash()を取得することにまったく頼ることはできません。

オーバーASCII文字列は、ハッシュが次のように文字列を形成する単一の文字で計算されるという理由だけで機能します:

_class string:
    def __hash__(self):
        if not self:
            return 0 # empty
        value = ord(self[0]) << 7
        for char in self:
            value = c_mul(1000003, value) ^ ord(char)
        value = value ^ len(self)
        if value == -1:
            value = -2
        return value
_

ここで、_c_mul_関数は、Cの場合のように(循環なしの)オーバーフロー(オーバーフローなし)です。

32
rewritten

ほとんどの回答は、これはプラットフォームが異なるためであることを示唆していますが、それ以外にもあります。 object.__hash__(self)のドキュメント から:

デフォルトでは、strbytes、およびdatetimeオブジェクトの__hash__()値は、予測不能なランダム値で「ソルト」されます。それらは個々のPythonプロセス内で一定のままですが、Pythonを繰り返し呼び出しても予測できません。

これは、辞書挿入の最悪の場合のパフォーマンスであるO(n²)の複雑さを悪用する慎重に選択された入力によって引き起こされるサービス拒否に対する保護を提供することを目的としています。詳細については、 http://www.ocert.org/advisories/ocert-2011-003.html を参照してください。

ハッシュ値を変更すると、dictssetsおよびその他のマッピングの反復順序に影響します。 Pythonはこの順序について保証していません(通常、32ビットと64ビットのビルド間で異なります)。

同じマシンで実行しても、呼び出しによって異なる結果が得られます。

_$ python -c "print(hash('http://stackoverflow.com'))"
-3455286212422042986
$ python -c "print(hash('http://stackoverflow.com'))"
-6940441840934557333
_

一方:

_$ python -c "print(hash((1,2,3)))"
2528502973977326415
$ python -c "print(hash((1,2,3)))"
2528502973977326415
_

環境変数 PYTHONHASHSEED も参照してください。

この変数が設定されていない場合、またはrandomに設定されている場合、ランダム値を使用して、strbytes、およびdatetimeオブジェクトのハッシュをシードします。

PYTHONHASHSEEDが整数値に設定されている場合、ハッシュランダム化の対象となる型のhash()を生成するための固定シードとして使用されます。

その目的は、インタープリター自体のセルフテストなどの反復可能なハッシュを許可すること、またはpythonプロセスのハッシュ値を共有することを許可することです。

整数は_[0, 4294967295]_の範囲の10進数でなければなりません。値_0_を指定すると、ハッシュのランダム化が無効になります。

例えば:

_$ export PYTHONHASHSEED=0                            
$ python -c "print(hash('http://stackoverflow.com'))"
-5843046192888932305
$ python -c "print(hash('http://stackoverflow.com'))"
-5843046192888932305
_
16
arekolek

ハッシュの結果は32ビットプラットフォームと64ビットプラットフォームで異なります

計算されたハッシュが両方のプラットフォームで同じになる場合、使用を検討してください

def hash32(value):
    return hash(value) & 0xffffffff
8

推測では、AppEngineはPython(-5768830964305142685は32ビットに収まらない)の64ビット実装を使用しており、Pythonは32異なる実装間で有意義に比較できるオブジェクトハッシュに依存することはできません。

6

これは、python 2.5:

def c_mul(a, b):
  return eval(hex((long(a) * b) & (2**64 - 1))[:-1])

def py25hash(self):
  if not self:
    return 0 # empty
  value = ord(self[0]) << 7
  for char in self:
    value = c_mul(1000003, value) ^ ord(char)
  value = value ^ len(self)
  if value == -1:
    value = -2
  if value >= 2**63:
    value -= 2**64
  return value

符号ビットはどうですか?

例えば:

16進値0xADFE74A5は、符号なし2919134373および符号付き-1375832923を表します。正しい値は署名されている必要があります(符号ビット= 1)が、pythonはそれを符号なしとして変換し、64ビットから32ビットへの変換後に不正なハッシュ値があります。

使用には注意してください:

def hash32(value):
    return hash(value) & 0xffffffff
5
Lion

文字列の多項式ハッシュ。 1000000009および239は任意の素数です。偶然衝突する可能性は低いです。モジュラー演算はそれほど高速ではありませんが、衝突を防ぐためには、2のべき乗をモジュロとするよりも信頼性が高くなります。もちろん、意図的に衝突を見つけるのは簡単です。

mod=1000000009
def hash(s):
    result=0
    for c in s:
        result = (result * 239 + ord(c)) % mod
    return result % mod
3
osa

[〜#〜] pythonhashseed [〜#〜] の値を使用して、ハッシュ値を初期化できます。

試してください:

PYTHONHASHSEED python -c 'print(hash('http://stackoverflow.com'))'
2
blueyed