본문 바로가기

Dataclasses

1. Dataclasses

dataclass는 Python 3.7에서 도입된 기능으로, 데이터를 저장하고 처리하기 위한 클래스를 효율적으로 생성할 수 있게 해주는 기능입니다. 주로 데이터 모델링에 사용되며, 반복적인 코드(보일러플레이트)를 줄여주는 역할을 합니다.

1.1 기본 사용법

일반적인 클래스와 dataclass의 차이를 비교해보겠습니다.

# 일반적인 클래스 정의
class User:
    def __init__(self, id, name, email):
        self.id = id
        self.name = name
        self.email = email
    
    def __repr__(self):
        return f"User(id={self.id}, name={self.name}, email={self.email})"
    
    def __eq__(self, other):
        if not isinstance(other, User):
            return NotImplemented
        return (self.id, self.name, self.email) == (other.id, other.name, other.email)
# dataclass를 사용한 방식
from dataclasses import dataclass

@dataclass
class User:
    id: int
    name: str
    email: str

user = User(123, 'hojun', 'hojun@gmail.com')
print(user)  # User(id=123, name='hojun', email='hojun@gmail.com')

1.2 주요 기능

1.2.1 기본값 설정

from dataclasses import dataclass

@dataclass
class Configuration:
    host: str = 'localhost'
    port: int = 8080
    debug: bool = False

config = Configuration()
print(config)  # Configuration(host='localhost', port=8080, debug=False)

1.2.2 불변 객체 생성

@dataclass(frozen=True)
class Settings:
    api_key: str
    timeout: int = 30

settings = Settings('my-secret-key')
print(settings)  # Settings(api_key='my-secret-key', timeout=30)
# settings.api_key = 'new-key'  # FrozenInstanceError 발생

1.3 고급 기능

1.3.1 필드 옵션 설정

dataclasses.field() 함수는 dataclass 필드의 동작을 세밀하게 제어할 수 있게 해주는 다양한 옵션을 제공합니다. 주요 옵션은 다음과 같습니다.

  • default: 기본값 설정
  • default_factory: 기본값을 동적으로 생성
  • init: 생성자에 포함할지 여부
  • repr: 객체를 문자열로 표현할 때 포함할지 여부
  • compare: 비교 연산자 생성 여부
from dataclasses import dataclass, field
from datetime import datetime

@dataclass
class User:
    id: int
    name: str
    email: str
    active: bool = True
    created_at: str = field(default_factory=lambda: datetime.now().isoformat())
    _search_string: str = field(init=False, repr=False)
    
    def __post_init__(self):
        self._search_string = f"{self.name}:{self.email}".lower()

user = User(1, "Hojun", "hojun@example.com")
print(user)  # created_at이 현재 시간으로 설정됨

1.3.2 상속

from datetime import datetime

@dataclass
class User:
    id: int
    name: str
    email: str
    active: bool = True
    created_at: str = field(default_factory=lambda: datetime.now().isoformat())
    _search_string: str = field(init=False, repr=False)
    
    def __post_init__(self):
        self._search_string = f"{self.name}:{self.email}".lower()

@dataclass
class Employee(User):
    salary: float = 0.0
    department: str = 'Engineering'

employee = Employee(1, "Hojun", "hojun@example.com", salary=50000)
print(employee)

1.3.3 비교 연산자 자동 생성

@dataclass(order=True)
class Number:
    value: int

numbers = [Number(3), Number(1), Number(2)]
print(sorted(numbers))  # [Number(value=1), Number(value=2), Number(value=3)]