과거에는 단순히 데이터만 담는 클래스(예: 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
대비 훨씬 깔끔하고 직관적인 현대적 코드 작성을 하는 방법을 소개하겠습니다.
'개발 이야기 > Python (파이썬)' 카테고리의 다른 글
[모던 Python 5편] concurrent.futures, asyncio로 동시성/병렬 코드 간소화하기 (0) | 2024.12.17 |
---|---|
[모던 Python 4편] pathlib로 직관적인 파일 경로 처리하기 (1) | 2024.12.17 |
[모던 Python 2편] 타입 힌트와 Mypy로 코드 명확성 강화하기 (0) | 2024.12.17 |
[모던 Python 1편] f-string: 문자열 포매팅의 현대적 방식 (0) | 2024.12.17 |
파이썬 3.14 (개발중): 새로운 기능과 개선사항 총정리 (0) | 2024.12.17 |