언어 Language/파이썬 Python

Q. 파이썬에서 데이터를 객체로 맵핑하는 방법은?

Tap to restart 2022. 6. 14. 20:00
반응형

A. 여러가지 방법으로 가능하다. 기본 __init__을 활용할 수도 있고, dataclasses, pydantic 등을 활용해서 할 수도 있다.

 

데이터를 받아서 데이터 모델 클래스의 객체object로 맵핑mapping하는 경우는 정말 많이 필요하다. 그렇지 않으면 일일이 변수로 만들거나 딕셔너리로 접근해야 하는데 너무 번거롭기 때문이다.

 

데이터를 객체로 만들어주는 팩키지나 라이브러리를 보통 객체 맵퍼 Object Mapper라고 부른다. 예를 들면 자바의 Jackson 같은 경우다. 파이썬에서는 어떻게 객체 맵핑을 할 수 있을까.

 

1. 가장 기본적인 방법

__init__ 을 활용하는 방법이다. 

class User:
    def __init__(self, name, phone, birthday):
        self.name = name
        self.phone = phone
        self.birthday = birthday


user_data = {
    "name": "taptorestart",
    "phone": "01013572468",
    "birthday": "1999-12-31"
}

user = User(**user_data)
print(user)
print(user.name)

 

위 코드를 실행하면 결과는 아래와 같다.

<__main__.User object at 0x7fb6900fbd60>
taptorestart

필요로 하는 모델 클래스의 속성이 많아질수록 번거롭다. 쓸데 없는 반복 코드 self., self. 를 계속 적어야 한다.

 

2. dataclasses를 활용하는 방법

아예 파이썬 3.7부터 dataclasses란 표준 라이브러리가 추가되었다. 

아래와 같은 형태로 입력하면 자동으로 객체 맵핑을 해준다. 완전 간단해졌다!

__init__ self.name 같은 거 쓸 필요 없다.

@dataclass
class User:
    name: str
    phone: str

당연하지만 어노테이션 쓰지 않으면 위처럼 클래스를 선언한다고 자동을 맵핑되지 않는다. 

반드시 @dataclass란 어노테이션을 써야한다.

 

from dataclasses import dataclass
from typing import Optional
from datetime import date


@dataclass
class User:
    name: str
    phone: str
    birthday: Optional[date]


user_data = {
    "name": "taptorestart",
    "phone": "01013572468",
    "birthday": "1999-12-31"
}

user = User(**user_data)
print(user)

user_data_without_birthday = {
    "name": "taptorestart",
    "phone": "01013572468",
}

user_without_birthday = User(**user_data_without_birthday)
print(user_without_birthday)

실행 결과

User(name='taptorestart', phone='01013572468', birthday='1999-12-31')
Traceback (most recent call last):
  File "main2.py", line 27, in <module>
    user_without_birthday = User(**user_data_without_birthday)
TypeError: __init__() missing 1 required positional argument: 'birthday'

Optional은 안 되는 것을 위 실행결과에서 확인할 수 있다.

 

3. pydantic을 사용하는 방법

pydantic은 객체 맵핑도 되고 필수가 아닌 선택값 Optional도 지원되며, 유효성 검사까지 해준다.

 

pydantic 예제

from datetime import date
from typing import Optional
from pydantic import BaseModel


class User(BaseModel):
    name: str
    phone: str
    birthday: Optional[date]


user_data = {
    "name": "taptorestart",
    "phone": "01013572468",
    "birthday": "1999-12-31"
}

user = User(**user_data)
print(user)

user_data_without_birthday = {
    "name": "taptorestart",
    "phone": "01013572468",
}

user_without_birthday = User(**user_data_without_birthday)
print(user_without_birthday)

user_data_with_wrong_birthday = {
    "name": "taptorestart",
    "phone": "01013572468",
    "birthday": "Today!"
}

user_with_wrong_birthday = User(**user_data_with_wrong_birthday)
print(user_with_wrong_birthday)

실행 결과

name='taptorestart' phone='01013572468' birthday=datetime.date(1999, 12, 31)
name='taptorestart' phone='01013572468' birthday=None
Traceback (most recent call last):
  File "main.py", line 35, in <module>
    user_with_wrong_birthday = User(**user_data_with_wrong_birthday)
  File "pydantic/main.py", line 341, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for User
birthday
  invalid date format (type=value_error.date)

 

필요에 따라 골라서 쓰면 된다. 더 많은 기능을 지원하는 attrs란 팩키지도 있다.

반응형