파이썬 프로그래밍을 하다 보면 종종 마주치게 되는 오류 중 하나가 바로 TypeError: unhashable type입니다. 이 오류는 보통 해시 가능하지 않은 타입의 객체를 딕셔너리의 키나 집합의 요소로 사용하려 할 때 발생합니다. 오늘은 이 오류가 발생하는 원인과 해결 방법에 대해 자세히 알아보겠습니다.
unhashable type 오류란?
TypeError: unhashable type 오류는 파이썬에서 해시(hash) 연산이 불가능한 객체를 해시 기반 자료구조에 사용하려 할 때 발생합니다. 파이썬에서 딕셔너리와 집합(set)은 내부적으로 해시 테이블을 사용하기 때문에, 이러한 자료구조에 사용되는 키나 요소는 반드시 해시 가능(hashable)해야 합니다.
해시 가능하다는 것은 객체가 생명 주기 동안 변하지 않는 해시 값을 가지고 있어야 하며, 다른 객체와 비교할 수 있어야 함을 의미합니다. 파이썬에서 모든 불변(immutable) 내장 객체는 해시 가능하지만, 변경 가능(mutable) 객체는 해시 불가능합니다.
해시 가능한 타입 vs 해시 불가능한 타입
해시 가능한 타입:
- 정수(int)
- 부동소수점(float)
- 문자열(str)
- 튜플(tuple) - 모든 요소가 해시 가능할 때
- frozenset
해시 불가능한 타입:
- 리스트(list)
- 딕셔너리(dict)
- 집합(set)
오류 발생 예시
다음은 TypeError: unhashable type 오류가 발생하는 대표적인 예시입니다:
# 리스트를 딕셔너리 키로 사용하려 할 때
my_dict = {[1, 2, 3]: "값"} # TypeError: unhashable type: 'list'
# 리스트를 집합에 추가하려 할 때
my_set = {1, 2, [3, 4]} # TypeError: unhashable type: 'list'
# 딕셔너리를 튜플에 넣어도 해시 불가능
my_tuple = ([1, 2], {3: 4})
my_set = {my_tuple} # TypeError: unhashable type: 'list'
해결 방법
1. 불변 객체로 변환하기
가장 일반적인 해결책은 해시 불가능한 객체를 해시 가능한 객체로 변환하는 것입니다:
# 리스트를 튜플로 변환
my_list = [1, 2, 3]
my_dict = {tuple(my_list): "값"} # 정상 작동
# 중첩된 구조인 경우
complex_list = [1, [2, 3]]
# 단순히 tuple(complex_list)는 여전히 오류 발생
2. frozenset 사용하기
집합을 딕셔너리 키로 사용해야 할 경우, frozenset을 사용할 수 있습니다:
my_set = {1, 2, 3}
my_dict = {frozenset(my_set): "값"} # 정상 작동
3. 사용자 정의 클래스 만들기
자신만의 클래스에서 해시 가능성을 제어하려면 __hash__와 __eq__ 메서드를 구현하면 됩니다:
class ImmutablePoint:
def __init__(self, x, y):
self._x = x
self._y = y
@property
def x(self):
return self._x
@property
def y(self):
return self._y
def __hash__(self):
return hash((self._x, self._y))
def __eq__(self, other):
if not isinstance(other, ImmutablePoint):
return False
return self._x == other._x and self._y == other._y
# 이제 이 객체는 딕셔너리 키로 사용 가능
point = ImmutablePoint(10, 20)
my_dict = {point: "좌표값"}
정리
TypeError: unhashable type 오류는 해시 테이블 기반 자료구조에 해시 불가능한 객체를 사용하려 할 때 발생합니다. 이 오류를 해결하려면:
- 가능하면 변경 가능한 객체(list, dict, set)를 불변 객체(tuple, frozenset)로 변환합니다.
- 복잡한 자료구조는 직렬화하여 문자열로 변환하는 방법도 있습니다.
- 사용자 정의 클래스의 경우
__hash__와__eq__메서드를 적절히 구현합니다.
파이썬에서 해시 가능성을 이해하면 더 효율적인 코드를 작성하고 이러한 유형의 오류를 방지할 수 있습니다. 딕셔너리와 집합은 파이썬의 강력한 도구이므로, 이들의 제약 사항을 알고 적절히 활용하는 것이 중요합니다.
댓글
댓글 쓰기