Python의 data transfer object 구현방식

햄도·2020년 12월 3일

Python에서는 데이터를 담기 위해 Dictionary나 Tuple을 자주 이용한다. 하지만 tuple의 경우 indexing으로 접근하기 때문에 값의 순서에 의존하게 되고 원소가 많아지면 몇번째 원소가 어떤 값이었는지 기억하기 힘들다. 또한 dict는 []를 이용해 속성에 접근해야 하기 때문에 덜 깔끔하다.

Python에서 DTO를 어떻게 구현하는 것이 가장 좋을까? 대표적으로는 아래 세 가지 방법이 있다.

  • Custom class
  • NamedTuple
  • Dataclass

Custom class

가장 기본적인 방법으로, 직접 DTO class를 만들 수 있다.

이때 property/setter annotation을 사용하면 더 깔끔하게 getter와 setter를 구현할 수 있다.

class Test:

    def __init__(self):
        self.__color = "red"

    @property
    def color(self):
        return self.__color

    @color.setter
    def color(self,clr):
        self.__color = clr

if __name__ == '__main__':

    t = Test()
    t.color = "blue"

    print(t.color)

# 출처: https://hamait.tistory.com/827 [HAMA 블로그]

NamedTuple

namedtuple을 이용해 더 간단하게 typing이 포함된 클래스를 만들 수 있다.

namedtuple은 collection 패키지와 typing 패키지에 존재하며, typing 패키지의 namedtuple은 python 3.6부터 사용할 수 있다.

from typing import NamedTuple

class Pruefer(NamedTuple):
    ident: int
	max_num: int
	name: str

Pruefer(1,4,"name")

Dataclass

python 3.7부터는 dataclass를 지원한다.

dataclass를 이용하면 더 깔끔해보이고, 기본값 지정 및 해싱이 가능하며 init 이나 repr 같은 특수 메소드를 custom class에 자동으로 추가해준다.

import dataclasses as dc

@dc.dataclass(unsafe_hash=True)
class Pruefer:
    ident : int
    maxnum : float = float("inf")
    name : str  = ""

pr = Pruefer(1, 2.0, "3")

pr
# Pruefer(ident=1, maxnum=2.0, name='3')

pr.ident
# 1

pr.maxnum
# 2.0

pr.name
# '3'

hash(pr)
# -5655986875063568239

dataclass vs. namedtuple vs. custom object

  • dataclass는 상태를 저장하는데에 최적화되어있기 때문에, 객체를 생성하고 읽는 작업을 빠르게 할 수 있다.
  • custom object는 중첩된 속성을 읽고 함수를 수행하는 데에 적합하다.
  • namedtuple은 생성만 빠르다.
  • Python 3.7 이상 Data-only object에서는 Dataclass가 좋다. function이 필요한 object는 custom class로 구현하는게 미세하게 빠르다.
  • Python 2의 경우 Data-only object는 namedtuple로, function이 필요한 object는 custom object로 구현하는 것이 좋다.

어떤 방식을 사용하는게 좋을까?

  • 객체에 들어갈 속성이 2~3개인 경우
    • 속성의 순서를 기억하기 쉽기때문에 plain tuple을 이용해도 괜찮다.
  • immutable 필드가 필요한 경우
    • plain tuple, collections.namedtuple, typing.NamedTuple을 이용하면 좋다.
  • 필드 이름을 고정하고, 오타를 방지하고 싶은 경우
    • collections.namedtuple, typing.NamedTuple을 이용하면 좋다.
  • 단순한게 최고야
    • JSON과 유사한 문법때문에 plain dictionary가 좋다.
  • 자료구조에 대해 full control을 필요로 하는 경우
  • object에 method가 필요한 경우
    • custom class를 만든다. 바닥부터 만들어도 되고, collections.namedtuple이나 typing.NamedTuple을 extend해도 괜찮다.
  • 데이터를 serialize해 disk나 network로 보내야 하는 경우
    • struct.Struct가 좋다.
profile
developer hamdoe

0개의 댓글