해시는 파이썬에서 무엇을합니까?


88

hash함수가 튜플에 적용되는 코드의 예를 보았습니다 . 결과적으로 음의 정수를 반환합니다. 이 기능이 무엇을하는지 궁금합니다. Google은 도움이되지 않습니다. 해시 계산 방법을 설명하는 페이지를 찾았지만이 함수가 필요한 이유를 설명하지 않습니다.


8
당신은 볼나요 문서 ...
terrya를

이 링크 (공식 문서)로 이동하십시오. 모든 것을 지정합니다. 링크 로 이동 !
tailor_raj

2
나는 질문이 "그것이 무엇인가"의 반복이 아니라 "우리가 그것을 필요로하는 이유"라는 점을 좋아합니다.
dnozay

공식 링크는 매우 혼란
Rasmi 란잔 나약를

답변:


156

해시는 특정 값을 식별하는 고정 된 크기의 정수입니다 . 각 값에는 고유 한 해시가 있어야하므로 동일한 값에 대해 동일한 객체가 아니더라도 동일한 해시를 얻게됩니다.

>>> hash("Look at me!")
4343814758193556824
>>> f = "Look at me!"
>>> hash(f)
4343814758193556824

해시 충돌 수를 줄이기 위해 결과 값이 균등하게 분산되도록 해시 값을 만들어야합니다. 해시 충돌은 두 개의 다른 값이 동일한 해시를 가질 때 발생합니다. 따라서 비교적 작은 변경으로 인해 종종 매우 다른 해시가 발생합니다.

>>> hash("Look at me!!")
6941904779894686356

이 숫자는 큰 값 모음에서 값을 빠르게 조회 할 수 있으므로 매우 유용합니다. 두 가지 사용 예는 Python setdict. 에서 list값이 목록에 있는지 확인하려면을 사용하여 if x in values:Python이 전체 목록을 살펴보고 목록의 x각 값 과 비교 해야합니다 values. 이것은 오랜 시간이 걸릴 수 있습니다 list. A의 set, 파이썬은 각 해시를 추적하고 입력 할 때 if x in values:, 파이썬의 해시 값을 얻을 것이다 x, 내부 구조에이를보고 만 비교 x와 동일한 해시를 가지고있는 값 x.

동일한 방법론이 사전 조회에 사용됩니다. 이에 조회 수 setdict조회에가있는 동안, 매우 빠른 list느립니다. 또한에는 해시 할 수없는 객체를 가질 수 list있지만에는 set또는 dict. 해시 할 수없는 객체의 일반적인 예는 변경 가능한 객체입니다. 즉, 값을 변경할 수 있습니다. 변경 가능한 객체가있는 경우 해시 할 수 없어야합니다. 해시가 수명에 따라 변경되어 객체가 사전에서 잘못된 해시 값으로 끝날 수 있기 때문에 많은 혼란을 야기 할 것입니다.

값의 해시는 한 번의 Python 실행에 대해서만 동일해야합니다. Python 3.3에서는 실제로 Python이 새로 실행될 때마다 변경됩니다.

$ /opt/python33/bin/python3
Python 3.3.2 (default, Jun 17 2013, 17:49:21) 
[GCC 4.6.3] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> hash("foo")
1849024199686380661
>>> 
$ /opt/python33/bin/python3
Python 3.3.2 (default, Jun 17 2013, 17:49:21) 
[GCC 4.6.3] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> hash("foo")
-7416743951976404299

이것은 특정 문자열이 가질 해시 값을 추측하기가 더 어렵습니다. 이는 웹 애플리케이션 등의 중요한 보안 기능입니다.

따라서 해시 값은 영구적으로 저장되지 않아야합니다. 해시 값을 영구적으로 사용해야하는 경우 파일 등의 확인 가능한 체크섬을 만드는 데 사용할 수있는 보다 "심각한"유형의 해시, 암호화 해시 함수를 살펴볼 수 있습니다.


12
잠재적 인 해시 충돌에 관하여 : hash(-1) == hash(-2)(파이썬 2.7를 박차 고)
마티아스

2
Python 3.6.1을 실행 중이며 충돌이 있습니다.
The_Martian

hash(-1) == hash(-2)오늘날에도 여전히 존재합니다. 다행히도 사전 및 세트 조회에 악영향을 미치지 않습니다. 다른 모든 정수 i에 대해 스스로 해결 hash(i)제외 -1.
Chris Conlan

36

TL; DR :

용어집을 참조하십시오 : hash()객체를 비교하는 지름길로 사용되며 다른 객체와 비교할 수있는 객체는 해시 가능한 것으로 간주됩니다. 그것이 우리가 hash(). 또한 액세스하는 데 사용 dict하고 set로 구현 요소 의 CPython에서 크기 조정 해시 테이블 .

기술적 고려 사항

  • 일반적으로 객체 비교 (여러 수준의 재귀가 포함될 수 있음)는 비용이 많이 듭니다.
  • 바람직하게는, hash()함수는 훨씬 저렴하다.
  • 두 개의 해시를 비교하는 것이 두 객체를 비교하는 것보다 쉽습니다. 바로 가기가 여기에 있습니다.

사전이 구현되는 방법대해 읽으면 해시 테이블을 사용합니다. 즉, 객체에서 키를 파생하는 것은의 사전에서 객체를 검색하는 초석이됩니다 O(1). 그러나 충돌 방지 기능은 해시 함수에 따라 크게 달라집니다 . 항목을 가져 오는 최악의 경우 사전에이 사실이다 O(n).

참고로 변경 가능한 객체는 일반적으로 해시 할 수 없습니다. hashable 속성은 객체를 키로 사용할 수 있음을 의미합니다. 해시 값이 키로 사용되고 동일한 객체의 내용이 변경되면 해시 함수는 무엇을 반환해야합니까? 동일한 키입니까 아니면 다른 키입니까? 그것은 따라 당신이 당신의 해시 함수를 정의하는 방법에.

예제로 배우기 :

이 클래스가 있다고 상상해보십시오.

>>> class Person(object):
...     def __init__(self, name, ssn, address):
...         self.name = name
...         self.ssn = ssn
...         self.address = address
...     def __hash__(self):
...         return hash(self.ssn)
...     def __eq__(self, other):
...         return self.ssn == other.ssn
... 

참고 : 이것은 모두 SSN이 개인에 대해 변경되지 않는다는 가정을 기반으로합니다 (신뢰할 수있는 출처에서 실제로 그 사실을 어디에서 확인해야할지조차 모릅니다).

그리고 우리는 Bob이 있습니다.

>>> bob = Person('bob', '1111-222-333', None)

Bob은 이름을 변경하기 위해 판사를 만나러갑니다.

>>> jim = Person('jim bo', '1111-222-333', 'sf bay area')

이것이 우리가 알고있는 것입니다.

>>> bob == jim
True

그러나 이들은 같은 사람에 대한 두 개의 다른 레코드처럼 할당 된 다른 메모리를 가진 두 개의 다른 개체입니다.

>>> bob is jim
False

이제 hash ()가 편리한 부분이 있습니다.

>>> dmv_appointments = {}
>>> dmv_appointments[bob] = 'tomorrow'

뭔지 맞춰봐:

>>> dmv_appointments[jim] #?
'tomorrow'

두 개의 다른 레코드에서 동일한 정보에 액세스 할 수 있습니다. 이제 이것을 시도하십시오.

>>> dmv_appointments[hash(jim)]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 9, in __eq__
AttributeError: 'int' object has no attribute 'ssn'
>>> hash(jim) == hash(hash(jim))
True

방금 무슨 일이 있었나요? 그것은 충돌입니다. hash(jim) == hash(hash(jim))둘 다 정수 btw 이기 때문에 __getitem__충돌하는 모든 항목과 의 입력을 비교해야합니다 . 내장 int에는 ssn속성이 없으므로 트립됩니다.

>>> del Person.__eq__
>>> dmv_appointments[bob]
'tomorrow'
>>> dmv_appointments[jim]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: <__main__.Person object at 0x7f611bd37110>

이 마지막 예제에서는 충돌이 있어도 비교가 수행되고 객체가 더 이상 동일하지 않음을 보여줍니다. 즉, KeyError.


정말 편리한 설명입니다. 초보자로서 이것은 세트에 넣을 수있는 클래스를 생성하고 사전 / 해시 테이블의 키로 사용하는 방법을 알아내는 데 도움이되었습니다. 또한 collection [hashable_obj] = hashable_obj를 수행하면 나중에 해당 인스턴스에 대한 포인터를 얻을 수 있습니다. 그러나 그러한 컬렉션을 추적하는 더 좋은 방법이 있는지 알려주십시오.
PaulDong

@dnozay 그러나 여전히의 출력은 hash()고정 된 크기의 정수로 충돌을 일으킬 수 있습니다.
overexchange

2
누군가 __eq__위의 예에서의 사용에 대해 자세히 설명 할 수 있습니까 ? 받은 키를 가지고있는 모든 키와 비교하려고 할 때 사전에 의해 호출됩니까? 마지막 예제 del__eq__메서드에 의해 사전은받은 키와 가지고있는 키의 동등성을 결정하는 데 사용할 호출이 없습니다.
Jet Blue

1
@JetBlue "collosion"설명은 key가있는 예제에서 불완전합니다 hash(jim). Person.__eq__기존 키가 hash(jim)올바른 키 Person.__eq__가 사용 되는지 확인하기 위해 동일한 해시를 가지고 있기 때문에 호출 됩니다. 인 에 속성 other이 있다고 가정하기 때문에 오류 int가 발생 ssn합니다. 경우 hash(jim)키가 사전에 존재하지 않았다 __eq__호출 할 수 없습니다 것입니다. 이것은 키 조회가 O (n) 일 수있는 경우를 설명합니다. 모든 항목이 동일한 해시 __eq__를 갖는 경우 (예 : 키가 존재하지 않는 경우).
WloHu

1
귀하의 예에 대한 교육적 관심을 이해하고 있지만 메서드 dmv_appointments[bob.ssn] = 'tomorrow'를 정의 할 필요없이을 작성하는 것이 더 간단하지 __hash__않습니까? 나는 당신이 쓰고 읽는 모든 약속에 4 문자를 추가한다는 것을 이해하지만 나에게는 더 명확 해 보입니다.
Alexis

3

상태에 대한hash() Python 문서 :

해시 값은 정수입니다. 사전 조회 중에 사전 키를 빠르게 비교하는 데 사용됩니다.

Python 사전은 해시 테이블로 구현됩니다. 따라서 사전을 사용할 때마다 hash()할당 또는 조회를 위해 전달하는 키에서 호출됩니다.

또한 유형 상태에 대한 문서dict :

해시 할 수없는 값 , 즉 목록, 사전 또는 기타 변경 가능한 유형 (객체 ID가 아닌 값으로 비교됨)을 포함하는 값은 키로 사용할 수 없습니다.


1

해시는 사전에 사용되며 개체를 빠르게 조회하도록 설정합니다. 좋은 출발점은 해시 테이블 에 대한 Wikipedia의 기사입니다 .


-2

Dictionary파이썬 에서 데이터 유형을 사용할 수 있습니다 . 해시와 매우 유사하며 중첩 된 해시와 유사한 중첩도 지원합니다.

예:

dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8; # update existing entry
dict['School'] = "DPS School" # Add new entry

print ("dict['Age']: ", dict['Age'])
print ("dict['School']: ", dict['School'])

자세한 내용 은 사전 데이터 유형에 대한이 자습서 를 참조하십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.