먼저 요약

list      : 내용 기반인데 내용이 변함     → hash 불안정 → 막힘
tuple     : 내용 기반인데 내용이 안 변함   → hash 안정   → OK
일반 객체   : id 기반이고 id는 안 변함     → hash 안정   → OK

List

먼저, hashable 관점에서의 Tuple에 대한 설명은 아래를 참조

[Python] 자료구조

hashable의 조건은 아래와 같음:

hashable의 필수 조건   
 1. "해시값이 **객체 수명 동안 안정적**일 것"
 2. "**== 기준과 hash 기준이 일치**할 것"

불변성은 이 조건을 만족시키는 흔한 수단일 뿐, 필수 조건은 아님

이로 인해서, 가변 객체도 hashable일 수 있음

list가 unhashable인 이유

일단 기본적으로 list의 == 는 “내용 기반

이로 인해서, [1, 2] == [1, 2]True

그리고 hashable 규약상 ==가 같으면 hash동일해야 함

근데 list는 내용이 변하는 특성을 가짐 (mutable)

이로 인해서 내용이 변경이 되면 hash도 변경이 되는 문제가 발생

→ 이로 인해서, 위에 hashable의 조건 2번이 깨짐

이러면 해시값이 불안정하면 저장 위치를 잃어버리고, 해당 위치에 대해서 찾아갈 수 없는 상황이 발생

따라서 Python은 list를 아예 unhashable로 막음

hash([1, 2]) # TypeError: unhashable type: ‘list”

그러면 일반 객체처럼 “id 기반”으로 만들면 되는거 아닌가?

기술적으로 가능하지만 하지 않음. 그러한 이유는:

a = [1, 2]
b = [1, 2]

# list를 id 기반 hash로 만들면:
hash(a)  # a의 주소 -> EX. 1000
hash(b)  # b의 주소 -> EX. 2000 <- 다름

a == b   # Ture (내용 기반은 그대로 유지)

이로 인한 hashable에 대한 모순이 발생:

a == b 는 True 인데
hash(a) != hash(b) -> **규칙 위반**

여기서 의문점, 그러면 list를 왜 이렇게 설계가 되었는지?

list는 계속 추가/삭제/수정/정렬하는 가변 컬렉션으로 쓰라고 만든 자료구조

값이 같은지 비교”하고 “자유롭게 변경”하는 게 핵심 용도

이 두 성질(내용 기반 ==가변 )이 합쳐지면서 구조적으로 hashable이 불가능해짐

그래서 키가 필요하면 tuple을 쓰라는 분업 구조로 설계

일반 객체

일반 객체는 ==주소 비교

일반 객체 두 개를 비교하면:

class User:
		def __init__(self, name):
				self.name = name
				
a = User("kim")
b = User("kim")

a == b   # False -> 내용은 동일하나 False

False가 나오는 이유는 일반 객체의 == 는 “내용이 같냐”가 아닌 “같은 객체(주소가 같냐)”를 봄

a == a   # True   (같은 객체, 주소 동일)
a == b   # False  (다른 객체, 주소 다름)

hash 도 동일하게 “주소 기반”

hash(a)  # a의 주소 기반 -> EX. 1000
hash(b)  # b의 주소 기반 -> EX. 2000