Python dataclass(frozen=True)로 불변 데이터 객체 만들기
문제
설정값이나 API 응답 데이터를 담는 객체를 만들었는데, 코드 어딘가에서 실수로 값이 변경되면 디버깅이 지옥이 된다. 딕셔너리로 넘기면 타입 힌트도 안 되고, 일반 클래스로 만들면 __setattr__ 오버라이드하고 난리를 쳐야 한다.
해결
dataclass(frozen=True)를 쓰면 한 줄로 해결된다.
from dataclasses import dataclass
@dataclass(frozen=True)
class DatabaseConfig:
host: str
port: int
name: str
max_connections: int = 10
config = DatabaseConfig(
host="localhost",
port=5432,
name="myapp"
)
# 값 변경 시도하면 에러 발생
config.port = 3306 # FrozenInstanceError!
__post_init__으로 생성 시점 검증도 가능하다.
@dataclass(frozen=True)
class PriceRange:
min_price: float
max_price: float
def __post_init__(self):
if self.min_price < 0:
# frozen이라 object.__setattr__ 사용
raise ValueError("min_price는 0 이상이어야 한다")
if self.min_price > self.max_price:
raise ValueError("min_price가 max_price보다 클 수 없다")
frozen dataclass는 해시 가능해서 딕셔너리 키나 set 원소로도 쓸 수 있다.
@dataclass(frozen=True)
class Coordinate:
x: float
y: float
visited = set()
visited.add(Coordinate(1.0, 2.0)) # set에 넣을 수 있다
핵심 포인트
@dataclass(frozen=True)로 불변 객체를 간단하게 생성- 속성 변경 시도 시
FrozenInstanceError발생 __post_init__으로 생성 시점 검증 가능- frozen dataclass는 hashable이라 dict 키나 set 원소로 사용 가능