Python의 data transfer object 구현방식

햄도·2020년 12월 3일
1

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개의 댓글