dataclass와 TypedDict는 모두 "데이터를 구조화"하기 위해 사용되지만, 그 본질과 용도가 완전히 다릅니다.
가장 쉽게 요약하자면 다음과 같습니다.
dataclass: 데이터를 가진 "객체(Object)"를 만들기 위한 도구TypedDict: 데이터가 담긴 "딕셔너리(Dictionary)"의 형태를 정의하는 도구상세한 차이점을 4가지 핵심 요소로 비교해 드리겠습니다.
이 부분이 코드를 작성할 때 가장 눈에 보이는 차이점입니다.
dataclass (객체 지향적): 점(.)을 사용하여 속성에 접근합니다. (Dot notation)book.title, book.isbnTypedDict (딕셔너리 방식): 키(Key)를 사용하여 접근합니다. (Bracket notation)book['title'], book['isbn']dataclass (가능): 클래스이기 때문에 데이터를 가공하거나 계산하는 함수(메서드)를 내부에 정의할 수 있습니다.@dataclass
class User:
name: str
age: int
def greeting(self):
return f"Hello, my name is {self.name}"TypedDict (불가능): 본질이 dict이므로, 데이터를 처리하는 로직(메서드)을 가질 수 없습니다. 오직 키와 값의 타입만 정의합니다.이 부분이 기술적으로 매우 중요합니다.
dataclass: 실행 시점에 실제로 새로운 타입의 객체가 메모리에 생성됩니다. type(book)을 찍어보면 해당 클래스 이름이 나옵니다.TypedDict: 실행 시점에 그냥 일반 dict입니다. TypedDict라는 이름은 오직 코드를 쓰기 전(정적 분석 단계)에 에디터가 도와주기 위해 존재하는 이름일 뿐입니다. 파이썬 엔진은 실행할 때 TypedDict가 무엇인지 신경 쓰지 않습니다.| 특징 | dataclass | TypedDict |
|---|---|---|
| 주 목적 | 도메인 모델링: 프로그램 내부에서 핵심이 되는 데이터 객체를 정의할 때 | 데이터 구조 정의: 외부(API, JSON, DB)에서 들어오는 딕셔너리의 형식을 맞출 때 |
| 주요 용도 | 복잡한 비즈니스 로직, 객체 지향 설계 | JSON 데이터 파싱, API 응답 규격 정의, 기존 dict 기반 코드의 타입 힌트 |
| 데이터 구조 | 클래스 인스턴스 | 표준 Python 딕셔너리 |
다음 질문에 따라 결정하세요.
"이 데이터에 어떤 동작(메서드)을 추가해야 하는가?"
dataclass를 사용하세요."이 데이터를 외부 시스템(JSON API, 설정 파일 등)과 주고받는 용도로만 쓰는가?"
TypedDict를 사용하세요. (딕셔너리 형태 그대로를 유지하는 것이 훨씬 편합니다.)dataclass를 사용하세요.예시 상황:
TypedDict를 사용하여 타입 힌트를 줍니다.dataclass를 사용합니다.실무에서 이 둘을 구분하는 기준은 "데이터가 프로그램 내부의 주인공인가(Logic), 아니면 단순히 전달되는 메시지인가(Data Transfer)?"입니다.
더 구체적인 실무 시나리오를 통해 각각 어떤 경우에 사용하는지 설명해 드리겠습니다.
dataclass를 사용하는 경우: "도메인 모델 (Domain Model)"실무에서 dataclass는 비즈니스 로직의 핵심이 되는 객체를 만들 때 사용합니다. 데이터가 단순히 담겨있는 것을 넘어, 그 데이터로 무엇을 할 것인가(행위)가 중요할 때 사용합니다.
실무 시나리오: 이커머스 주문 시스템
주문(Order) 정보는 단순히 데이터만 있는 게 아니라, "할인 적용", "총 금액 계산", "배송 가능 여부 확인" 같은 기능(Method)이 필요합니다.
from dataclasses import dataclass
from datetime import datetime
@dataclass
class Order:
order_id: str
items: list[str]
price_per_item: int
quantity: int
created_at: datetime
# 비즈니스 로직 (메서드)
def calculate_total(self) -> int:
return self.price_per_item * self.quantity
def is_recent(self) -> bool:
# 주문이 최근 24시간 이내에 생성되었는지 확인
return (datetime.now() - self.created_at).days < 1
# 실무 활용: 시스템 내부에서 주문 객체를 주고받으며 다양한 기능을 수행함
my_order = Order("ORD-001", ["Laptop"], 1500000, 1, datetime.now())
print(my_order.calculate_total()) # 기능을 수행할 수 있음
TypedDict를 사용하는 경우: "데이터 전송 객체 (DTO / Interface)"실무에서 TypedDict는 프로그램의 경계(Boundary)에서 사용됩니다. 즉, 외부 시스템(API, DB, 설정 파일)과 데이터를 주고받을 때 "데이터가 이렇게 생겼어"라고 규격을 정의할 때 사용합니다.
실무 시나리오: 외부 API 응답 처리
웹 서버가 사용자에게 보내주는 JSON 응답은 항상 dict 형태입니다. 이 JSON의 구조가 어떻게 생겼는지 명시하여, 개발자가 실수하지 않게 돕는 용도입니다.
from typing import TypedDict
# 외부 API(예: Google Map API)가 주는 응답 규격 정의
class LocationResponse(TypedDict):
lat: float
lng: float
address: str
is_verified: bool
# 실무 활용: API 호출 결과(dict)를 처리할 때
# 실제로는 requests.get().json() 등으로 받은 데이터임
api_data: LocationResponse = {
"lat": 37.5665,
"lng": 126.9780,
"address": "Seoul, Korea",
"is_verified": True
}
# 딕셔너리이므로 메서드는 없지만, IDE의 자동완성으로 오타를 방지함
print(api_data['address'])
| 구분 | dataclass | TypedDict |
|---|---|---|
| 현장 용어 | Domain Model (도메인 모델) | DTO / Schema (데이터 전송 객체/스키마) |
| 주요 위치 | 애플리케이션의 심장부 (Core Logic) | 애플리케이션의 입구와 출구 (API/DB/File) |
| 데이터의 역할 | "이 데이터는 이런 행위를 할 수 있어" | "이 데이터는 이런 형태로 생겼어" |
| 예시 시나리오 | 사용자(User), 주문(Order), 결제(Payment) | API 응답(Response), 설정값(Config), JSON 구조 |
| 데이터 접근 | user.name (속성 중심) | user['name'] (키 중심) |
최근 실무(특히 FastAPI 같은 현대적인 웹 프레임워크)에서는 이 두 가지의 장점만을 결합한 Pydantic라는 라이브러리를 매우 많이 사용합니다.
TypedDict처럼 데이터의 형태를 엄격하게 검사하고(Validation),dataclass처럼 클래스 형태로 정의하여 메서드도 가질 수 있게 해줍니다.따라서 공부하실 때 TypedDict (데이터 구조 정의) dataclass (객체 지향 설계) Pydantic (데이터 검증 및 모델링) 순서로 확장하며 학습하시면 실무에 가장 완벽히 대비할 수 있습니다.