데이터 엔지니어링

Pydantic 기본 사용법과 활용 사례

라이크나우 2024. 12. 22. 17:00

요즘은 데이터를 다양한 소스(API, 파일, 데이터베이스 등)에서 수집하고 이를 처리하거나 전달해야 하는 일을 주로 진행하고 있습니다. 특히 외부API에서 데이터를 수집하고 있는데 이 과정에서 데이터의 무결성을 보장하기 위한 방식으로 Pydantic을 사용하고 있어 자세히 알아보았습니다.


Pydantic 소개

Pydantic은 Python에서 데이터 유효성 검증과 데이터 직렬화를 위해 설계된 라이브러리입니다. FastAPI와 같은 최신 웹 프레임워크에서 요청 및 응답 데이터를 처리하는 데 필수적인 역할을 하고 있으며 데이터를 안전하고 효율적으로 관리할 수 있도록 도와줍니다.

 

주요 특징

  • 타입 기반 데이터 검증: Python의 타입 힌트를 활용해 데이터의 유효성을 자동으로 검사합니다.
  • 자동 데이터 변환: 정의된 타입에 따라 문자열을 숫자로 변환하거나 JSON 데이터를 Python 객체로 자동 매핑합니다.
  • 성능 최적화: 데이터 검증 및 변환 과정이 최적화되어 있어 대규모 데이터 처리에도 적합합니다.

기본 사용법

Model 정의

Pydantic에서 데이터 모델은 BaseModel을 상속받아 정의합니다. 이 모델은 Python의 데이터 클래스를 확장하며 타입 힌트를 사용해 필드의 데이터 타입과 구조를 명시합니다.

 

사용자의 정보를 정의하려면 다음과 같이 작성할 수 있습니다:

from pydantic import BaseModel

class User(BaseModel):
    id: int
    name: str
    email: str

 

Validation (검증)

Pydantic은 모델의 필드에 대해 자동으로 유효성 검증을 수행합니다. 잘못된 데이터가 제공되면 예외가 발생하며 데이터의 일관성을 보장할 수 있습니다.

 

아래와 같이 ValueError가 직관적으로 표현되기 때문에 데이터타입을 검증할 때에 유용합니다.

data = {"id": "abc", "name": "Rio", "email": "rio@example.com"}

try:
    user = User(**data)
except ValueError as e:
    print(e)
# Output: value is not a valid integer

 

또한 추가적인 검증 로직을 정의할 수 있는 @validator 데코레이터를 제공합니다.

특정 컬럼에 대해서는 추가적인 검증을 가독성 좋게 추가할 수 있습니다:

from pydantic import BaseModel, validator

class User(BaseModel):
    id: int
    name: str
    email: str

    @validator('email')
    def validate_email(cls, v):
        if "@" not in v:
            raise ValueError("Invalid email address")
        return v

 

Optional 필드와 기본값

선택적 필드와 기본값을 쉽게 정의할 수 있습니다. 이를 통해 필드가 반드시 제공되지 않아도 되는 경우를 처리할 수 있습니다.

다음은 기본값과 선택적 필드를 사용하는 예제입니다:

from typing import Optional
from pydantic import BaseModel

class User(BaseModel):
    id: int
    name: str = "Unknown"
    email: Optional[str]

data = {"id": 123}
user = User(**data)
print(user)
  • name 필드는 기본값으로 "Unknown"을 가집니다.
  • email 필드는 선택 사항이며 제공되지 않은 경우 None이 됩니다.

FastAPI와 함께 쓰기

Pydantic은 FastAPI와 매우 긴밀하게 통합되어 있으며 두 라이브러리를 조합하여 사용하는 경우가 많습니다. Pydantic은 FastAPI를 위해 만들어진 라이브러리는 아니지만 FastAPI가 처음부터 Pydantic을 기본 도구로 채택하면서 통합되었다고 합니다.

 

FastAPI와 Pydantic의 시너지

  1. 자동 데이터 검증: FastAPI는 요청(Request) 및 응답(Response) 데이터를 처리할 때 Pydantic 모델을 사용하여 자동으로 유효성을 검증합니다. 이를 통해 클라이언트에서 잘못된 데이터를 보내도 서버에서 즉시 에러를 반환할 수 있습니다.
  2. 간결한 코드: Pydantic 모델을 FastAPI 엔드포인트에서 직접 사용함으로써 데이터 구조 정의와 검증 로직이 단순화됩니다.
  3. OpenAPI 문서화: Pydantic 모델을 기반으로 FastAPI는 자동으로 API 문서를 생성합니다. 이를 통해 개발자는 Swagger UI에서 API 스펙을 직관적으로 확인할 수 있습니다.

예제: FastAPI에서 Pydantic 모델 사용하기

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    price: float
    description: Optional[str] = None

@app.post("/items/")
async def create_item(item: Item):
    return {"name": item.name, "price": item.price, "description": item.description}

위 코드에서는 Item이라는 Pydantic 모델을 정의하고 이를 FastAPI 엔드포인트에서 사용합니다. 클라이언트가 데이터를 보낼 때 Pydantic이 이를 검증하고 서버에서 처리할 수 있습니다.

 


Pydantic을 사용하게 된 이유와 후기

왜 Pydantic을 선택했는가?

위에서 말했듯이 저는 다양한 데이터 소스에서 데이터를 수집해야했기에 데이터 무결성을 보장하는 코드를 작성해야했습니다.

기존에는 다음과 같은 방식으로 데이터를 검증하고 처리했습니다:

  • 단순 조건문이나 정규식을 사용해 데이터 유효성을 검사
  • 잘못된 데이터가 들어올 경우 예외 처리 코드 추가

그러나 이러한 방식으로 진행하니 시간이 지남에 따라 코드가 복잡해지고 유지보수가 어렵다는 문제가 있었습니다. 이런 문제를 해결하기 위해 Pydantic을 도입하게 되었습니다.

 

Pydantic 사용 후 달라진 점

1. 코드 간결화

Pydantic의 가장 큰 장점은 데이터 검증과 변환을 간단한 모델 정의로 해결할 수 있다는 점입니다. 사용자 데이터를 처리해야 하는 경우 기존에는 여러 조건문과 함수로 구현해야 했던 작업을 간단하게 처리할 수 있었습니다.

 

2. 데이터 오류 조기 발견

Pydantic은 데이터가 모델에 적합하지 않을 경우 즉시 에러를 발생시킵니다. 이로 인해 잘못된 데이터를 사전에 차단할 수 있어 런타임에 발생하는 버그를 크게 줄일 수 있었습니다.

실제 서비스에서 API 요청을 처리할 때 이런 사전 검증은 서비스의 안정성을 크게 높이는 데 기여했습니다.

 

3. 유연성과 확장성

Pydantic은 기본값 처리, Optional 필드, 커스텀 검증 로직 등 실무에서 필요한 대부분의 요구를 쉽게 충족시켰습니다. 기본값과 선택적 필드를 통해 데이터 누락 상황에서도 유연하게 대응할 수 있었고 커스텀 Validator로 timestamp에 해당하는 컬럼 등의 복잡한 검증 로직을 간단히 추가할 수 있었습니다.

 


결론

Pydantic은 생산성, 안정성, 유지보수성을 크게 향상시키는 도구였습니다. 특히 데이터 검증이 중요한 프로젝트에서 초기 개발 속도를 높이고 런타임 에러를 줄이는 데 결정적인 역할을 했습니다. FastAPI와 같은 웹 프레임워크와의 조합은 개발 과정 전체를 더욱 매끄럽게 만든다는 생각이 들어서 앞으로도 잘 사용할 예정입니다!

 

 

 

참고 자료: