# 기존 방식: 보일러플레이트 코드가 많음
class User:
def __init__(self, name, age, email=""):
self.name = name
self.age = age
self.email = email
def __repr__(self):
return f"User(name={self.name!r}, age={self.age!r}, email={self.email!r})"
def __eq__(self, other):
if not isinstance(other, User):
return False
return self.name == other.name and self.age == other.age and self.email == other.email
# dataclass: 위 코드와 동일한 기능, 단 4줄
@dataclass
class User:
name: str
age: int
email: str = ""
| 장점 | 설명 |
|---|
| 간결함 | __init__, __repr__, __eq__ 자동 생성 |
| 타입 힌트 | 필드 타입 명시로 가독성/IDE 지원 향상 |
| 불변성 | frozen=True로 쉽게 불변 객체 생성 |
| 비교/정렬 | order=True로 비교 연산자 자동 생성 |
| 유틸리티 | asdict(), replace() 등 편의 함수 제공 |
from dataclasses import dataclass
@dataclass
class User:
name: str
age: int
email: str = "" # 기본값
# __init__, __repr__, __eq__ 자동 생성
user = User("Alice", 25)
user # User(name='Alice', age=25, email='')
user1 = User("Alice", 25)
user2 = User("Alice", 25)
user1 == user2 # True (__eq__ 자동 생성)
from dataclasses import dataclass, field
@dataclass
class Post:
title: str
content: str
tags: list = field(default_factory=list) # 가변 객체 기본값
views: int = field(default=0, repr=False) # repr에서 제외
_id: int = field(default=0, compare=False) # 비교에서 제외
# field 주요 옵션
field(
default=..., # 기본값
default_factory=..., # 가변 객체 기본값 (list, dict 등)
repr=True, # __repr__에 포함 여부
compare=True, # __eq__에 포함 여부
hash=None, # __hash__에 포함 여부
init=True, # __init__에 포함 여부
)
@dataclass(frozen=True)
class Point:
x: float
y: float
p = Point(1.0, 2.0)
p.x = 3.0 # FrozenInstanceError! (수정 불가)
# frozen=True → __hash__ 자동 생성 (딕셔너리 키로 사용 가능)
points = {Point(0, 0): "origin"}
@dataclass
class Rectangle:
width: float
height: float
area: float = field(init=False) # __init__에서 제외
def __post_init__(self):
self.area = self.width * self.height
rect = Rectangle(3, 4)
rect.area # 12
@dataclass
class Person:
name: str
age: int
@dataclass
class Employee(Person):
employee_id: str
department: str = "General"
emp = Employee("Alice", 30, "E001")
emp # Employee(name='Alice', age=30, employee_id='E001', department='General')
@dataclass(
init=True, # __init__ 생성
repr=True, # __repr__ 생성
eq=True, # __eq__ 생성
order=False, # __lt__, __le__, __gt__, __ge__ 생성
frozen=False, # 불변 객체
slots=False, # __slots__ 사용 (Python 3.10+)
kw_only=False, # 모든 필드를 키워드 전용으로 (Python 3.10+)
)
class MyClass:
...
# order=True 예시
@dataclass(order=True)
class Version:
major: int
minor: int
patch: int
Version(2, 0, 0) > Version(1, 9, 9) # True
from dataclasses import asdict, astuple, fields, replace
@dataclass
class User:
name: str
age: int
user = User("Alice", 25)
# 딕셔너리/튜플 변환
asdict(user) # {'name': 'Alice', 'age': 25}
astuple(user) # ('Alice', 25)
# 필드 정보 조회
fields(user) # (Field(name='name',...), Field(name='age',...))
# 복사 후 일부 값 변경
new_user = replace(user, age=26)
new_user # User(name='Alice', age=26)
@dataclass(slots=True)
class Point:
x: float
y: float
# 장점: 메모리 절약, 속성 접근 속도 향상
# 단점: 동적 속성 추가 불가
p = Point(1.0, 2.0)
p.z = 3.0 # AttributeError!
# 설정 객체
@dataclass(frozen=True)
class Config:
host: str = "localhost"
port: int = 8080
debug: bool = False
# DTO (Data Transfer Object)
@dataclass
class UserDTO:
id: int
username: str
email: str
@classmethod
def from_dict(cls, data: dict):
return cls(**data)
def to_dict(self):
return asdict(self)
# JSON 직렬화
import json
@dataclass
class Item:
name: str
price: float
item = Item("Book", 29.99)
json.dumps(asdict(item)) # '{"name": "Book", "price": 29.99}'