파이썬 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)에서 동일한 결과를 제공하는 해시 함수를 어떻게 가질 수 있습니까?
다음 과 같은 용도 hash()
로 설계된 hashlib 를 사용하십시오 .
사전 조회 중 사전 키를 빠르게 비교
따라서 Python 구현에서 동일하다는 것을 보장하지 않습니다.
문서에서 언급했듯이 내장 hash () 함수는 결과 해시를 외부 어딘가에 저장하도록 설계 되지 않았습니다 . 객체의 해시 값을 제공하고 사전에 저장하는 데 사용됩니다. 또한 구현에 따라 다릅니다 (GAE는 Python의 수정 된 버전을 사용함). 확인 :
>>> class Foo:
... pass
...
>>> a = Foo()
>>> b = Foo()
>>> hash(a), hash(b)
(-1210747828, -1210747892)
보시다시피 hash ()는 __hash__
SHA와 같은 '정상적인'해싱 알고리즘 대신 객체의 메서드를 사용하기 때문에 다릅니다 .
위의 상황에서 합리적인 선택은 hashlib 모듈 을 사용하는 것 입니다.
반응은 전혀 놀라운 일이 아닙니다. 사실
In [1]: -5768830964305142685L & 0xffffffff
Out[1]: 1934711907L
따라서 ASCII 문자열에 대해 신뢰할 수있는 응답 을 얻으려면 하위 32 비트를 uint
. 문자열에 대한 해시 함수는 32 비트 안전하고 거의 이식 가능합니다.
반면에 메서드를 불변 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에서와 같이 "순환"곱셈 (오버플로 없음)입니다.
대부분의 답변은 이것이 다른 플랫폼 때문이라고 제안하지만 더 많은 것이 있습니다. 에서 의 문서object.__hash__(self)
:
기본적
__hash__()
으로str
,bytes
및datetime
객체 의 값은 예측할 수없는 임의의 값으로 "염장"됩니다. 개별 Python 프로세스 내에서 일정하게 유지되지만 반복되는 Python 호출 간에는 예측할 수 없습니다.이는 dict 삽입의 최악의 경우 성능 인 O (n²) 복잡성을 악용하는 신중하게 선택한 입력으로 인한 서비스 거부에 대한 보호를 제공하기위한 것입니다. 자세한 내용은 http://www.ocert.org/advisories/ocert-2011-003.html 을 참조하십시오.
해시 값을 변경하면 반복의 순서에 영향을
dicts
,sets
그리고 다른 매핑을. 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
의 해시를 시드하는 데 임의의 값이 사용됩니다 .str
bytes
datetime
경우
PYTHONHASHSEED
정수 값으로 설정되어, 그것은 생성 고정 시드로 사용되는hash()
해시 랜덤 적용 유형에있다.그 목적은 인터프리터 자체에 대한 자체 테스트와 같이 반복 가능한 해싱을 허용하거나 파이썬 프로세스 클러스터가 해시 값을 공유하도록 허용하는 것입니다.
The integer must be a decimal number in the range
[0, 4294967295]
. Specifying the value0
will disable hash randomization.
For example:
$ export PYTHONHASHSEED=0
$ python -c "print(hash('http://stackoverflow.com'))"
-5843046192888932305
$ python -c "print(hash('http://stackoverflow.com'))"
-5843046192888932305
Hash results varies between 32bit and 64bit platforms
If a calculated hash shall be the same on both platforms consider using
def hash32(value):
return hash(value) & 0xffffffff
At a guess, AppEngine is using a 64-bit implementation of Python (-5768830964305142685 won't fit in 32 bits) and your implementation of Python is 32 bits. You can't rely on object hashes being meaningfully comparable between different implementations.
This is the hash function that Google uses in production for 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
What about sign bit?
For example:
Hex value 0xADFE74A5
represents unsigned 2919134373
and signed -1375832923
. Currect value must be signed (sign bit = 1) but python converts it as unsigned and we have an incorrect hash value after translation from 64 to 32 bit.
Be careful using:
def hash32(value):
return hash(value) & 0xffffffff
Polynomial hash for strings. 1000000009
and 239
are arbitrary prime numbers. Unlikely to have collisions by accident. Modular arithmetic is not very fast, but for preventing collisions this is more reliable than taking it modulo a power of 2
. Of course, it is easy to find a collision on purpose.
mod=1000000009
def hash(s):
result=0
for c in s:
result = (result * 239 + ord(c)) % mod
return result % mod
The value of PYTHONHASHSEED might be used to initialize the hash values.
Try:
PYTHONHASHSEED python -c 'print(hash('http://stackoverflow.com'))'
It probably just asks the operating system provided function, rather than its own algorithm.
As other comments says, use hashlib or write your own hash function.
참고URL : https://stackoverflow.com/questions/793761/built-in-python-hash-function
'Nice programing' 카테고리의 다른 글
ES6 + 자바 스크립트 모듈 내보내기 옵션 (0) | 2020.10.06 |
---|---|
Android에서 View와 ViewGroup의 차이점 (0) | 2020.10.06 |
mysql 테이블 열 데이터 유형을 얻는 방법은 무엇입니까? (0) | 2020.10.06 |
JavaScript로 사용자 에이전트 가져 오기 (0) | 2020.10.06 |
Gcc 오류 : gcc : 'cc1'exec 시도 오류 : execvp : 해당 파일 또는 디렉토리가 없습니다. (0) | 2020.10.06 |