본문 바로가기
Python Object-oriented Programming

__hash__ Method

by 자동매매 2023. 4. 3.

 

Hash?
해시란 단방향 암호화 기법으로 해시함수를 이용하여 고정된 길이의 비트열로 변경한다.
(여기서 단방향 암호화 기법은 암호화는 수행하지만 복호화는 불가능한 알고리즘을 말한다.)
이때 매핑 전 원래 데이터의 값을 , 매핑 후 데이터의 값을 해시값, 매핑하는 과정을 해싱, 해시값+데이터색인 주소를 해시테이블이라고 한다.

Hashable?

수명 주기 동안, 결코 변하지 않는(immutable) 해시값을 갖고 있고(__hash__ method), 다른 객체와 비교할 수 있으면(__eq__ method) 객체를 해시가능하다고 한다. 동일(==)하다고 판단되는 객체는 반드시 해시값이 동일해야 한다.

 

Introduction to the Python hash function

 

먼저 Person 클래스를 name age 특성으로 정의합니다.

 

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

 

둘째, Person 클래스의 인스턴스를 만듭니다.

 

p1 = Person('John', 22)
p2 = Person('Jane', 22)

 

셋째, p1 p2 객체 해시를 표시합니다.

 

print(hash(p1))
print(hash(p2))

Output:

110373112736
110373572343

 

hash()함수는 객체를 받아들이고 해시 값을 정수로 반환합니다. hash() 함수에 객체를 전달하면 Python 객체의 __hash__ 특수 메서드를 실행합니다.

이는 p1 객체를 hash() 함수 전달함을 의미합니다.

 

hash(p1)

 

파이썬은 p1 객체 __hash__ 메서드를 호출합니다:

 

p1.__hash__()

 

 

기본적으로,  __hash__  개체의 ID 사용하고  __eq__    개체가 동일한 경우 True 반환합니다.

기본 동작을 재정의하려면 __eq__ __hash__ 를 override을 구현할 있습니다.

 

클래스가 __eq__ 메서드를 override하면  클래스의 개체를 해시할 없게 됩니다.

Person 개체는 __eq__ 를 override를 구현하면 __hash__ 는 None으로 설정되기  때문에 해시가 손실됩니다. 

예를 들어:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __eq__(self, other):
        return isinstance(other, Person) and self.age == other.age

 

hash(Person('John', 22))

Error:

TypeError: unhashable type: 'Person'

 

또한 __eq__ method를 override하면 mapping type에서 그 개체를 사용할 없음을 의미합니다.

예를 들어 사전 키나 집합 요소로  이들을 사용할 없습니다Set에서 Person 개체를 사용하려고  하면 오류가 발생합니다.

 

members = {
    Person('John', 22),
    Person('Jane', 22)
}

 

파이썬은 다음 오류를 발행합니다 :

 

TypeError: unhashable type: 'Person'

 

Person 클래스를 __eq__ 메서드 override후 해시 가능하게 만들려면, __hash__ 메서드 구현해야 합니다.

 

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __eq__(self, other):
        return isinstance(other, Person) and self.age == other.age

    def __hash__(self):
        return hash(self.age)

이제 age 기반한 equal logic 지원하고  해시 가능한 Person 클래스를 갖는다.

 

Person  사전과 같은 데이터 구조에서 작동하도록 하려면 클래스의 해시가 변경 불가능한 상태로 유지되어야 합니다.

이렇게 하려면 Person 클래스의 age 속성을 read-only property(읽기 전용 속성)으로 만든다.

 

class Person:
    def __init__(self, name, age):
        self.name = name
        self._age = age

    @property
    def age(self):
        return self._age

    def __eq__(self, other):
        return isinstance(other, Person) and self.age == other.age

    def __hash__(self):
        return hash(self.age)

 

Summary

 

  • 기본적으로 __hash__  개체의 ID 사용하여 해시값을 반환한다. (  __eq__  비교를 위해 is 연산자   사용 )
  •  __eq__ 구현(override)하는 경우 __hash__ 를 구현하지 않으면 Python은  __hash__  None으로  설정합니다.
    [해결책] __hash__ 메서드를 override 구현
  • __eq__ 구현(override)하는 경우,  mapping type에서 그 개체를 사용할  없다.
    [해결책] 해시가 변경 불가능한 상태로 유지해야함, hash함수 관련 속성을 read-only property(읽기 전용 속성)으로 설정하고,  __hash__ 구현
 

'Python Object-oriented Programming' 카테고리의 다른 글

Dependency Inversion Principle  (0) 2023.04.04
__bool__ Method  (0) 2023.04.03
__eq__ Method  (0) 2023.04.03
__repr__ Method  (0) 2023.04.03
__str__ Method  (0) 2023.04.03

댓글