hash함수가 튜플에 적용되는 코드의 예를 보았습니다 . 결과적으로 음의 정수를 반환합니다. 이 기능이 무엇을하는지 궁금합니다. Google은 도움이되지 않습니다. 해시 계산 방법을 설명하는 페이지를 찾았지만이 함수가 필요한 이유를 설명하지 않습니다.
hash함수가 튜플에 적용되는 코드의 예를 보았습니다 . 결과적으로 음의 정수를 반환합니다. 이 기능이 무엇을하는지 궁금합니다. Google은 도움이되지 않습니다. 해시 계산 방법을 설명하는 페이지를 찾았지만이 함수가 필요한 이유를 설명하지 않습니다.
답변:
해시는 특정 값을 식별하는 고정 된 크기의 정수입니다 . 각 값에는 고유 한 해시가 있어야하므로 동일한 값에 대해 동일한 객체가 아니더라도 동일한 해시를 얻게됩니다.
>>> 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
이것은 특정 문자열이 가질 해시 값을 추측하기가 더 어렵습니다. 이는 웹 애플리케이션 등의 중요한 보안 기능입니다.
따라서 해시 값은 영구적으로 저장되지 않아야합니다. 해시 값을 영구적으로 사용해야하는 경우 파일 등의 확인 가능한 체크섬을 만드는 데 사용할 수있는 보다 "심각한"유형의 해시, 암호화 해시 함수를 살펴볼 수 있습니다.
hash(-1) == hash(-2)(파이썬 2.7를 박차 고)
hash(-1) == hash(-2)오늘날에도 여전히 존재합니다. 다행히도 사전 및 세트 조회에 악영향을 미치지 않습니다. 다른 모든 정수 i에 대해 스스로 해결 hash(i)제외 -1.
용어집을 참조하십시오 : 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.
hash()고정 된 크기의 정수로 충돌을 일으킬 수 있습니다.
__eq__위의 예에서의 사용에 대해 자세히 설명 할 수 있습니까 ? 받은 키를 가지고있는 모든 키와 비교하려고 할 때 사전에 의해 호출됩니까? 마지막 예제 del의 __eq__메서드에 의해 사전은받은 키와 가지고있는 키의 동등성을 결정하는 데 사용할 호출이 없습니다.
hash(jim). Person.__eq__기존 키가 hash(jim)올바른 키 Person.__eq__가 사용 되는지 확인하기 위해 동일한 해시를 가지고 있기 때문에 호출 됩니다. 인 에 속성 other이 있다고 가정하기 때문에 오류 int가 발생 ssn합니다. 경우 hash(jim)키가 사전에 존재하지 않았다 __eq__호출 할 수 없습니다 것입니다. 이것은 키 조회가 O (n) 일 수있는 경우를 설명합니다. 모든 항목이 동일한 해시 __eq__를 갖는 경우 (예 : 키가 존재하지 않는 경우).
dmv_appointments[bob.ssn] = 'tomorrow'를 정의 할 필요없이을 작성하는 것이 더 간단하지 __hash__않습니까? 나는 당신이 쓰고 읽는 모든 약속에 4 문자를 추가한다는 것을 이해하지만 나에게는 더 명확 해 보입니다.
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'])
자세한 내용 은 사전 데이터 유형에 대한이 자습서 를 참조하십시오 .