데이터 저장에 최적화된 dataclass를 소개합니다.
dataclass는 class에 여러 dunder (직역하면 찌꺼기, 의미상 자질구레한 것들) 를 추가하여 class를 보다 편리하게 data container로 사용할 수 있도록 해줍니다.
일반적인 class는, __init__() 도 직접 작성해야 하고, 모든 attribute의 값이 동일하더라도 서로 다른 instance라면 다른 것으로 간주합니다.
class Book:
author: str
title: str
def __init__(self, author: str, title: str = 'Default Title'):
self.author = author
self.title = title
x = Book(author='Kenneth', title='My Biography')
y = Book(author='Kenneth', title='My Biography')
x == y # False
하지만 dataclass를 사용하면, __init__도 직접 생성해주고 __eq__를 바꿔 값을 비교하게 합니다.
@dataclass
class Book:
author: str
title: str = 'Default Title'
x = Book(author='Kenneth', title='My Biography')
y = Book(author='Kenneth', title='My Biography')
x == y # True
dataclass 인자에 frozen=True를 넘겨 값을 변경하는 것을 방지할 수도 있고, (물론 원천 불가하게는 안되고 object.__setattr__()은 사용 가능합니다) 기본값에 dataclasses.fields를 이용해서 필드마다 더 구체적으로 설정할 수 있습니다.
namedtuple은 tuple처럼 기본적으로 sequential한 데이터에서 index 대신 name으로 접근할 필요가 있을때 쓴다고 보면 맞습니다. 그렇기에 데이터가 sequential하지 않다면 namedtuple보다는 dataclass가 합리적인 선택입니다.
비슷한 역할을 수행할 수 있으면서도, 구현을 생각해보면 실행속도나 메모리 점유 측면에서 차이가 날만한 부분들이 있습니다. 그래서 잘 정리되어 있는 글을 열심히 찾아봤지만 맘에 드는 수준으로 정리된건 결국 못찾았습니다. 구글링하면 최상단에 떠오르는 이런 글도 있는데, gist 링크가 깨져서 어떻게 그렇게 결론이 나온건지 이해가 안가는 부분들이 좀 있습니다. 일단 여기서는 미세한 차이가 있다 정도로만 정리하겠습니다.
namedtuple이 손이 잘 안 가는 클래스라 당장은 생각이 없지만, 나중에 이 주제가 흥미로워진다면 좀 더 자세하게 python 문서와 코드를 살펴보고 직접 비교하는 글을 작성해볼까 싶기도 합니다.
// 2020-01-21 추가
간단하고 러프하게 퍼포먼스 비교를 해봤습니다. (링크) 생성 및 attribute access 속도에 있어 약 10% 이내의 차이로 namedtuple이 더 빠른 것을 확인할 수 있었습니다.
작년 초, 프로젝트에서 특정 계약에 제공되는 피쳐와 그 피쳐에 대한 상세정보를 기록해야 하는 부분이 있었습니다. 계약마다 세부 내용이 다르기도 하고, 서비스가 발전하면서 제공하는 피쳐도 늘어나기 때문에 유동적으로 관리하는 한편, 항목 자체는 명시적일 필요도 있었지요. 당시에는 여러 이슈도 있고 실력도 부족해서 nested dict를 사용했지만, attribute 대신 subscript로 가져와야 한다는 점이 항상 불편했습니다. 지금 다시 작업한다면 dataclass를 사용해봐도 좋겠다는 생각이 듭니다.