2023-01-04 22:26:44

Flask보다 각광받고 있는 파이썬 웹 프레임워크 중 하나인 FastAPI를 사용하려다 보면 pydantic이라는 라이브러리를 저절로 접하게 됩니다. FastAPI의 공식 문서를 살펴보면, FastAPI는 Pydantic과 Starlette라는 두 거인의 어깨 위에 있다고 표현되어 있습니다[2]. 그만큼 pydantic이 중요한 친구라는 거겠죠. 

 

Fast API stands on the shoulders of giants:
- Starlette for the web parts.
- Pydantic for the data parts.

 

Pydantic이란

Pydantic의 공식 문서[1]를 보면, Pydantic에 대해 다음과 같이 설명합니다. 

 

Data validation and settings management using Python type annotations.
pydantic enforces type hints at runtime, and provides user friendly errors when data is invalid.
Define how data should be in pure, canonical Python; validate it with pydantic.

 

pydantic은 파이썬 타입 주석(type annotations)을 사용하여 데이터의 유효성을 검증해주는 파이썬 라이브러리입니다. 제가 현재까지 파악한 바로 pydantic의 주된 기능은 다음과 같습니다. 

1) 데이터 유효성 검증

2) 데이터 파싱(형 변환)

 

간단한 예제를 통해 pydantic의 기능을 이해해보겠습니다. 우선 pip install pydantic으로 pydantic을 설치해주세요. 패키지 관리자로 poetry를 사용하시는 분이시라면 poetry add pydantic으로 설치하시면 됩니다. 

 

1) 데이터 유효성 검증

from pydantic import BaseModel


class User(BaseModel):
    name: str
    age: int


user1 = User(name='john', age=15)
print(user1)

user2 = User(name='tom', age='ten')
print(user2)

 

pydantic의 BaseModel 클래스를 상속받아서 User라는 클래스를 만드는데, name의 타입은 str로, age의 타입은 int로 정해줍니다. 이렇게 한 다음 데이터 타입을 맞게 해서 user1 객체를 생성하면 에러 없이 제대로 생성되지만, 데이터 타입에 맞지 않게 해서 user2 객체를 생성하면 에러가 납니다. 

 

 

위와 같이 User 객체의 age 값은 정수여야 한다고 사용자 친화적인 에러 메시지를 던져줍니다. 

 

2) 데이터 파싱

from pydantic import BaseModel


class User(BaseModel):
    name: str
    age: int


user1 = User(name='john', age=15)
print(user1)

user2 = User(name='tom', age='10')
print(user2)

 

위 코드를 실행하면 정수 데이터가 들어가야할 age에 '10'이라는 문자열 데이터가 들어갔음에도 정수 10으로 데이터 형 변환이 이뤄졌습니다. 데이터를 적절히 파싱해낸 것입니다. 

 

 

데이터 클래스란

데이터 클래스를 아시는 분들은 Pydantic과 데이터클래스와 상당히 유사하다는 것을 발견하셨을 것입니다. 참고로 데이터클래스는 파이썬 3.7부터 표준 라이브러리에 추가된 것으로 "데이터를 담기 위한 클래스"입니다. 그냥 클래스를 사용하는 것보다 데이터를 담기 위한 용도로 사용할 때는 편한 점이 많습니다. __init__() 메소드를 선언할 필요가 없고, __repr__() 메소드도 자동으로 생성해줍니다. 위에서 Pydantic으로 구현했던 클래스를 이번에는 data class로 구현해보겠습니다. 

 

1) 데이터 유효성 검증 (X)

from dataclasses import dataclass


@dataclass
class User:
    name: str
    age: int


user1 = User(name='john', age=15)
print(user1)

user2 = User(name='tom', age='ten')
print(user2)

 

위 코드를 실행해보면 데이터 클래스를 사용한 경우에는 에러가 나지 않습니다. 데이터클래스에서는 타입 힌트(타입 어노테이션)의 역할만 수행합니다. age가 int 타입이어야 한다고 명시되어 있지만, 다른 타입의 데이터가 들어오더라도 수용합니다. 데이터 유효성 검증을 하지 않습니다. 

 

 

2) 데이터 파싱 (X)

또한 아래 예제를 실행해보면 데이터 파싱도 하지 않는다는 것을 알 수 있습니다.

 

from dataclasses import dataclass


@dataclass
class User:
    name: str
    age: int


user1 = User(name='john', age=15)
print(user1)

user2 = User(name='tom', age='10')
print(user2)

 

 

즉, 데이터 클래스는 데이터를 담기 위한 클래스의 역할에만 충실할 뿐 데이터 유효성 검사나 데이터 파싱까지 하진 않습니다.

 

정리하며

참고로 pydantic은 설정값 관리에도 많이 쓰입니다. vault와 같은 키 저장소에서 가져온 키들을 pydantic의 BaseModel 클래스를 상속받아 만든 클래스에 담곤 합니다.

 

제가 pydantic과 dataclass에 대해 이해한 부분에 있어서 잘못된 점이 있다면 과감히 지적해주시고 알려주시면 감사하겠습니다. 

 

참고자료

[1] https://pydantic-docs.helpmanual.io/   

[2] https://fastapi.tiangolo.com/