[모던 Python 3편] dataclass로 데이터 구조 간소화하기

과거에는 단순히 데이터만 담는 클래스(예: DTO, VO)를 정의할 때도 __init__, __repr__, __eq__ 등을 일일이 작성해야 했습니다. 그러나 Python 3.7부터 @dataclass 데코레이터를 사용하면 이러한 반복적인 코드를 자동으로 생성할 수 있어, 데이터 구조 정의가 훨씬 단순해집니다.

이번 글에서는 전통적인 클래스 구현 방식과 dataclass를 비교하고, dataclass 사용 시 장단점, 주의점을 살펴봅니다.

이전에는 어떻게 했을까?

전통적인 클래스 구현 예

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __repr__(self):
        return f"Person(name={self.name}, age={self.age})"

    def __eq__(self, other):
        if not isinstance(other, Person):
            return False
        return self.name == other.name and self.age == other.age
  • 장점: Python 모든 버전에서 동작, 익숙한 패턴
  • 단점: __init__, __repr__, __eq__ 등을 수동 구현 필요. 필드 하나 추가할 때마다 초기화 코드, 출력 코드 수정 필요. 보일러플레이트 증가.

특히 데이터만 담는 "단순한" 클래스에서도 매번 같은 패턴을 반복 작성해야 하는 비효율이 존재.

데이터클래스(dataclass) 도입

@dataclass 데코레이터는 최소한의 코드로 동일한 기능을 제공하며, 필드 정의를 기반으로 __init__, __repr__, __eq__ 등을 자동 생성합니다.

from dataclasses import dataclass

@dataclass
class Person:
    name: str
    age: int

위 코드만으로도 Person 인스턴스를 생성하면 자동으로 다음과 같은 기능이 제공됩니다:

  • __init__(name: str, age: int) 자동 생성
  • __repr__ 자동 생성 → Person(name='Alice', age=30) 형태 출력
  • __eq__ 자동 생성 → 같은 필드값이면 True 반환

장점:

  • 보일러플레이트 코드 감소: 간단한 데이터 구조 정의 시코드량 대폭 감소
  • 명확한 데이터 모델링: 클래스 본문에 필드 타입을 바로 명시, 가독성↑
  • 기존 클래스 대비 생산성 향상

단점:

  • Python 3.7+ 필요(3.6에서는 dataclasses 백포트를 설치해야 함)
  • 매우 복잡한 로직이 들어간 클래스에는 적합하지 않을 수 있음 (dataclass는 주로 단순 데이터 홀더에 적합)
  • 필드 기본값, mutable default 처리 시 주의 필요 (mutable 객체를 필드 기본값으로 두는 경우 field(default_factory=...) 활용 권장)

추가 기능: 필드 옵션

dataclasses.field()를 이용하면 특정 필드에 대해 default_factory나 비교/해시 여부를 제어할 수 있습니다.

from dataclasses import dataclass, field
from typing import List

@dataclass
class PersonGroup:
    people: List['Person'] = field(default_factory=list)

이렇게 하면 빈 리스트를 기본값으로 사용하는데, 하나의 리스트 객체가 모든 인스턴스에서 공유되지 않고, 인스턴스 생성 시마다 새 리스트가 생성됩니다.

성능 측면

dataclass는 주로 개발 생산성, 가독성, 유지보수 측면에서 이점이 있으며, 성능 면에서 일반 클래스와 큰 차이는 없습니다. 다만 __init__, __repr__, __eq__를 직접 작성할 필요가 없어 인적 오류와 관리 부담을 줄여 장기적으로 개발 속도를 높이는 효과가 있습니다.

결론

  • dataclass를 사용하면 단순 데이터 구조 정의가 극단적으로 쉬워지고, 보일러플레이트 코드가 사라집니다.
  • Python 3.7+ 환경에서 지원, 이전 버전 호환 필요 시 dataclasses 백포트 사용 가능.
  • 간단한 레코드/DTO/모델 객체 정의에 dataclass를 활용해 코드를 현대화하고 유지보수성을 높일 수 있습니다.

다음 글에서는 파일/경로 처리를 위한 pathlib 사용법을 살펴보며, os.path 대비 훨씬 깔끔하고 직관적인 현대적 코드 작성을 하는 방법을 소개하겠습니다.

반응형