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


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 set과 dict. 에서 list값이 목록에 있는지 확인하려면을 사용하여 if x in values:Python이 전체 목록을 살펴보고 목록의 x각 값 과 비교 해야합니다 values. 이것은 오랜 시간이 걸릴 수 있습니다 list. A의 set, 파이썬은 각 해시를 추적하고 입력 할 때 if x in values:, 파이썬의 해시 값을 얻을 것이다 x, 내부 구조에이를보고 만 비교 x와 동일한 해시를 가지고있는 값 x.

동일한 방법론이 사전 조회에 사용됩니다. 이에 조회 수 set와 dict조회에가있는 동안, 매우 빠른 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.