반응형

 

dataclass란?

Python 3.7에서 도입된 dataclass는 데이터를 저장하기 위한 클래스를 쉽게 생성할 수 있게 해주는 데코레이터이다. 보일러플레이트 코드를 줄이고 데이터 중심의 클래스를 더 효율적으로 작성할 수 있게 해준다.

전통적인 클래스에서는 __init__, __repr__, __eq__ 등의 특수 메서드를 직접 구현해야 했지만, dataclass를 사용하면 이러한 메서드들이 자동으로 생성된다.

 

1. 기본 사용법

클래스 정의 위에 @dataclass 데코레이터를 추가하고, 각 필드의 타입을 명시하면 완전한 기능을 갖춘 클래스가 생성된다.

from dataclasses import dataclass

@dataclass
class Book:
    title: str
    author: str
    price: float
    in_stock: bool = True

# 사용 예시
book = Book("파이썬 완벽 가이드", "홍길동", 25000)
print(book)  # Book(title='파이썬 완벽 가이드', author='홍길동', price=25000, in_stock=True)

여기서 dataclass는 자동으로 다음을 생성한다:

  • __init__ 메서드: 객체 초기화를 위한 생성자
  • __repr__ 메서드: 객체의 문자열 표현을 위한 메서드
  • __eq__ 메서드: 객체 간 비교를 위한 메서드

 

2. 클래스 변수와 인스턴스 변수

dataclass에서는 클래스 변수와 인스턴스 변수의 선언 방식이 일반 클래스와 다르다. 

  • 인스턴스 변수 - 타입 어노테이션이 없음
  • 클래스 변수 - 1. 타입 어노테이션이 없거나 2. ClassVar[타입]이 명시되있음

기본적인 구분 방법

from dataclasses import dataclass
from typing import ClassVar

@dataclass
class Student:
    # 인스턴스 변수 (타입 어노테이션 필수)
    name: str
    age: int
    
    # 클래스 변수 (타입 어노테이션 없음)
    school_name = "파이썬 고등학교"
    
    # 타입 힌트가 있는 클래스 변수
    MAX_AGE: ClassVar[int] = 20

 

3. 고급 기능

3.1 필드 옵션 설정

field() 함수를 사용하면 필드의 동작을 더 세밀하게 제어할 수 있다. default_factory를 사용하여 가변 객체의 기본값을 안전하게 설정하거나, init=False로 초기화에서 제외할 수 있다.

from dataclasses import dataclass, field

@dataclass
class Student:
    name: str
    scores: list[int] = field(default_factory=list)
    average: float = field(init=False)
    
    def __post_init__(self):
        self.average = sum(self.scores) / len(self.scores) if self.scores else 0

3.2 불변 데이터클래스 만들기

데이터의 불변성이 필요한 경우, frozen 매개변수를 사용하여 인스턴스의 속성을 변경할 수 없게 만들 수 있다. 이는 설정값이나 상수 데이터를 다룰 때 특히 유용하다.

@dataclass(frozen=True)
class Configuration:
    host: str
    port: int = 8080
    
config = Configuration("localhost")
# config.port = 9000  # 이 코드는 FrozenInstanceError를 발생시킨다

3.3 상속 활용하기

dataclass도 일반 클래스처럼 상속을 지원한다. 이를 통해 코드 재사용성을 높이고 계층적인 데이터 구조를 만들 수 있다.

@dataclass
class Vehicle:
    brand: str
    model: str
    year: int

@dataclass
class Car(Vehicle):
    doors: int = 4
    fuel_type: str = "gasoline"

 

4. Best Practice와 주의사항

4.1 타입 힌트 활용하기

dataclass는 타입 힌트와 함께 사용할 때 가장 효과적이다. IDE의 자동 완성과 타입 검사 기능을 최대한 활용할 수 있다.

from typing import Optional

@dataclass
class User:
    username: str
    email: str
    age: Optional[int] = None

4.2 기본값 설정 시 주의 사항(가변 객체 다루기)

dataclass에서 가변 객체(list, dict, set 등)를 다룰 때는 특별한 주의가 필요하다. 기본값으로 직접 가변 객체를 할당하면 모든 인스턴스가 같은 객체를 공유하게 되어 예기치 않은 버그가 발생할 수 있다. 이를 방지하기 위해 field(default_factory=)를 사용해야 한다.

# 잘못된 예시
@dataclass
class Wrong:
    items: list = []  # 모든 인스턴스가 같은 리스트를 공유

# 올바른 예시
@dataclass
class Right:
    items: list = field(default_factory=list)  # 각 인스턴스가 독립적인 리스트를 가짐

4.3 불변성 고려하기

데이터의 무결성이 중요한 경우 frozen=True 사용을 고려하는 것이 좋다. 실수로 인한 데이터 변경을 방지하고 함수형 프로그래밍 스타일을 지원할 수 있다.

4.4 클래스 변수와 인스턴스 변수 배치

코드의 가독성과 유지보수성을 높이기 위해서는 클래스 내의 변수들을 일관된 순서로 배치해야 한다. 인스턴스 변수를 먼저 선언하고, 그 다음에 클래스 변수를 선언하는 것이 권장된다.

@dataclass
class Example:
    # 1. 먼저 인스턴스 변수(필드)를 선언
    name: str
    value: int
    
    # 2. 그 다음 ClassVar를 사용한 클래스 변수
    VERSION: ClassVar[str] = "1.0"
    MAX_VALUE: ClassVar[int] = 100
    
    # 3. 마지막으로 일반 클래스 변수
    status = "active"

 

결론

dataclass는 데이터를 다루는 클래스를 작성할 때 매우 유용한 도구이다. 보일러플레이트 코드를 줄이고, 가독성을 높이며, 실수를 줄일 수 있다. 특히 데이터 모델링, API 응답 처리, 설정 관리 등에서 큰 효과를 발휘한다.

반응형

+ Recent posts