python-error-handling은(는) 무엇을 하나요?
Python 오류 처리 패턴: 입력 유효성 검사, 예외 계층 구조, 부분 실패 처리. 검증 로직 구현, 예외 전략 설계, 배치 처리 실패 처리 또는 견고한 API 구축 시 사용하세요.
개요
이 스킬은 Python 애플리케이션에서 오류를 효과적으로 처리하기 위한 모범 사례와 패턴을 제공합니다. 입력 유효성 검사, 예외 계층 구조 설계, 부분 실패 처리를 중점적으로 다룹니다.
주요 패턴
1. 입력 유효성 검사
from dataclasses import dataclass
from typing import Optional
from enum import Enum
class UserRole(Enum):
ADMIN = "admin"
USER = "user"
GUEST = "guest"
@dataclass
class UserInput:
name: str
age: int
role: UserRole
def validate_user_input(data: dict) -> Optional[str]:
"""사용자 입력 검증. 오류 메시지를 반환하거나 None을 반환."""
if not data.get("name"):
return "이름은 필수입니다."
if not isinstance(data.get("age"), int) or data["age"] < 0:
return "유효한 나이를 입력하세요."
try:
UserRole(data.get("role", "user"))
except ValueError:
return f"유효하지 않은 역할: {data.get('role')}"
return None
2. 예외 계층 구조
class AppError(Exception):
"""애플리케이션 기본 예외."""
def __init__(self, message: str, code: int = 500):
self.message = message
self.code = code
super().__init__(self.message)
class ValidationError(AppError):
"""입력 검증 실패 시 발생."""
def __init__(self, message: str, field: str = None):
self.field = field
super().__init__(message, code=400)
class NotFoundError(AppError):
"""리소스를 찾을 수 없을 때 발생."""
def __init__(self, message: str, resource_id: str = None):
self.resource_id = resource_id
super().__init__(message, code=404)
class BusinessError(AppError):
"""비즈니스 규칙 위반 시 발생."""
def __init__(self, message: str, code: int = 409):
super().__init__(message, code)
3. 부분 실패 처리
from dataclasses import dataclass, field
from typing import List, TypeVar, Generic
T = TypeVar("T")
E = TypeVar("E")
@dataclass
class Result(Generic[T, E]):
"""성공 또는 실패를 나타내는 결과 타입."""
value: T = None
error: E = None
is_success: bool = True
def process_batch(items: List[dict]) -> List[Result]:
"""배치 처리: 각 항목의 성공/실패를 개별 수집."""
results = []
for item in items:
try:
processed = process_item(item)
results.append(Result(value=processed))
except Exception as e:
results.append(Result(error=str(e), is_success=False))
return results
4. 검증 데코레이터
from functools import wraps
from typing import Callable, Any
def validate_input(schema: type) -> Callable:
"""입력 검증 데코레이터."""
def decorator(func: Callable) -> Callable:
@wraps(func)
def wrapper(*args, **kwargs):
data = kwargs.get("data", {})
error = validate_user_input(data)
if error:
raise ValidationError(error)
return func(*args, **kwargs)
return wrapper
return decorator
API 예시
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/users", methods=["POST"])
@validate_input(UserInput)
def create_user():
data = request.get_json()
# 유효성 검사는 데코레이터에서 처리됨
user = create_user_in_db(data)
return jsonify(user), 201
@app.errorhandler(AppError)
def handle_app_error(error):
response = {"error": error.message}
return jsonify(response), error.code
모범 사례
- 조기에 실패, 명확하게 실패: 가능한 빨리 입력을 검증하고 명확한 오류 메시지를 제공하세요.
- 풍부한 예외 사용: 의미 있는 속성(예: 오류 코드, 필드 이름)을 가진 사용자 정의 예외를 만드세요.
- 부분 실패 처리: 배치 처리 시 오류가 한 항목에 국한되도록 하고, 전체 작업을 중단하지 마세요.
- 결과 타입 활용: 성공/실패를 명시적으로 표현하는
Result타입을 도입하세요. - 데코레이터로 관심사 분리: 검증 로직을 비즈니스 로직에서 분리하세요.
참고
- 이 패턴들은 Flask, FastAPI, Django 등 모든 Python 프레임워크와 호환됩니다.
- 자세한 내용은 Python 공식 문서를 참조하세요.