

파이썬을 어느 정도 학습한 이후에는 "데이터를 어떻게 표현할 것인가?"가 매우 중요한 주제가 됩니다.
실무에서는 다음과 같이 사용하는 경우가 많습니다.
아래에서 하나씩 비교해보겠습니다.
| 항목 | 일반 Class | NamedTuple | dataclass | BaseModel(Pydantic) |
|---|---|---|---|---|
| 목적 | 객체지향 프로그래밍 | 읽기 전용 데이터 | 데이터 저장 | 데이터 검증 + 직렬화 |
| Mutable | O | X | O (기본) | O (기본) |
| Immutable 가능 | 직접 구현 | 기본 제공 | frozen=True | frozen=True |
| 생성자 자동 생성 | X | O | O | O |
| repr 자동 | X | O | O | O |
| 비교(eq) 자동 | X | O | O | O |
| 타입 힌트 | 선택 | O | O | O |
| 런타임 타입 검사 | X | X | X | O |
| JSON 변환 | 직접 작성 | 직접 작성 | asdict() | model_dump(), model_dump_json() |
| Validation | X | X | X | 매우 강력 |
| 속도 | 빠름 | 매우 빠름 | 빠름 | 상대적으로 느림 |
| 메모리 | 보통 | 매우 적음 | 적음 | 가장 큼 |
| 실무 사용 빈도 | ★★★★☆ | ★★☆☆☆ | ★★★★★ | ★★★★★ |
| 상황 | 추천 |
|---|---|
| 비즈니스 로직이 많다 | 일반 Class |
| 좌표, RGB, Point처럼 변경되지 않는 데이터 | NamedTuple |
| 대부분의 DTO, Entity | dataclass |
| FastAPI Request/Response | BaseModel |
| JSON 검증 | BaseModel |
| DB Entity | dataclass |
| 설정 파일(Config) | BaseModel |
| 계산 객체 | 일반 Class |
예를 들어 쇼핑몰의 상품을 생각해보겠습니다.
class Product:
"""
상품 클래스
데이터뿐 아니라
상품의 동작(비즈니스 로직)도 함께 가진다.
"""
def __init__(self, name: str, price: int):
# 상품명
self.name = name
# 가격
self.price = price
def discount(self, percent: int):
"""
할인 적용
예:
percent = 20
-> 가격을 20% 할인
"""
self.price = int(self.price * (100 - percent) / 100)
def print_info(self):
"""상품 정보 출력"""
print(f"상품명 : {self.name}")
print(f"가격 : {self.price:,}원")
product = Product("노트북", 1800000)
product.print_info()
product.discount(10)
product.print_info()
상품명 : 노트북
가격 : 1,800,000원
상품명 : 노트북
가격 : 1,620,000원
✔ 객체지향에 적합
✔ 기능(메서드)을 많이 넣을 수 있음
✔ 상속에 유리
읽기 전용(Immutable) 데이터입니다.
좌표처럼 변경되면 안 되는 데이터를 표현할 때 좋습니다.
from typing import NamedTuple
class Point(NamedTuple):
"""
2차원 좌표
한번 생성되면 수정할 수 없다.
"""
x: int
y: int
point = Point(10, 20)
print(point.x)
print(point.y)
# point.x = 100
# AttributeError 발생
10
20
x, y = point
print(x)
print(y)
class RGB(NamedTuple):
red: int
green: int
blue: int
이미지 처리에서 자주 사용됩니다.
가장 많이 사용하는 데이터 객체입니다.
from dataclasses import dataclass
@dataclass
class Customer:
"""
고객 정보
__init__
__repr__
__eq__
를 자동 생성한다.
"""
id: int
name: str
age: int
customer = Customer(
id=1,
name="홍길동",
age=25
)
print(customer)
출력
Customer(id=1, name='홍길동', age=25)
customer.age = 30
print(customer)
a = Customer(1, "홍길동", 25)
b = Customer(1, "홍길동", 25)
print(a == b)
출력
True
from dataclasses import asdict
print(asdict(customer))
출력
{
'id':1,
'name':'홍길동',
'age':30
}
전자상거래 주문 Entity
from dataclasses import dataclass
@dataclass
class Order:
"""
주문 Entity
"""
order_id: int
customer: str
total_price: int
ORM 없이 간단한 프로젝트에서 많이 사용됩니다.
실무에서 FastAPI를 사용한다면 가장 많이 만나는 클래스입니다.
from pydantic import BaseModel, Field
class User(BaseModel):
"""
회원 가입 데이터
입력값을 자동 검증한다.
"""
name: str
age: int = Field(
ge=0,
le=120
)
email: str
user = User(
name="홍길동",
age=25,
email="test@test.com"
)
print(user)
User(
name="홍길동",
age=-5,
email="abc@test.com"
)
결과
ValidationError
age
Input should be greater than or equal to 0
print(user.model_dump())
출력
{
"name":"홍길동",
"age":25,
"email":"test@test.com"
}
print(user.model_dump_json())
FastAPI Request
from pydantic import BaseModel, EmailStr, Field
class RegisterRequest(BaseModel):
"""
회원가입 요청 모델
클라이언트가 보낸 데이터를
자동으로 검증한다.
"""
username: str = Field(min_length=3, max_length=20)
password: str = Field(min_length=8)
email: EmailStr
클라이언트가 잘못된 이메일이나 너무 짧은 비밀번호를 보내면 Pydantic이 자동으로 검증하여 오류를 반환합니다.
| 계층 | 사용하는 객체 |
|---|---|
| API Request | BaseModel |
| API Response | BaseModel |
| Service | 일반 Class |
| Domain Entity | dataclass |
| Repository | dataclass |
| 설정(Config) | BaseModel |
| Value Object | NamedTuple 또는 @dataclass(frozen=True) |
데이터를 표현하려는가?
│
┌────────┴────────┐
│ │
검증이 필요한가? 비즈니스 로직이 많은가?
│ │
┌────┴────┐ ┌──┴──┐
│ │ │ │
예 아니오 예 아니오
│ │ │ │
BaseModel dataclass Class Immutable?
│
┌──────┴──────┐
│ │
예 아니오
│ │
NamedTuple 또는 dataclass
@dataclass(frozen=True)
파이썬 중급 과정에서는 다음 순서로 학습하면 개념이 자연스럽게 연결됩니다.
일반 클래스(Class): 객체지향의 기본 원리와 캡슐화, 메서드 설계
NamedTuple: 불변(Immutable) 데이터와 경량 객체
dataclass: 데이터 중심 객체와 자동 메서드 생성
Pydantic BaseModel: 데이터 검증, 직렬화, API 모델링
추가 심화 주제
__slots__를 이용한 메모리 최적화@dataclass(frozen=True)를 활용한 불변 객체field(default_factory=...)와 __post_init__()typing.Protocol과 ABC를 활용한 인터페이스 설계attrs 라이브러리와 dataclass 비교Pydantic v2의 field_validator, computed_field, model_validator 활용