티스토리 뷰

파이썬의 데코레이터

데코레이터(decorater)는 데코레이터 이후에 나오는 것을 데코레이터의 첫 번째 파라미터로 하고 데코레이터의 결과 값을 반환하게 하는 문법적 설탕(syntax sugar)이다.

데코레이터라는 이름은 래핑된 함수의 기능을 수정하고 확장하기  때문에 정확한 이름이지만, "데코레이터 디자인 패턴"과 혼동하면 안된다.

 

함수 데코레이터

함수에 데코레이터를 사용하면 어떤 종류의 로직이라도 적용할 수 있다. 파라미터의 유효성을 검사하거나 사전조건을 검사하거나, 기능 전체를 새롭게 정의할 수도 있고, 서명을 변경할 수도 있고, 원래 함수의 결과를 캐시하는 등의 작업을 모두 할 수 있다.

 

#decorator_function_1.py

class ControlledExeption(Exeption):
    """도메인에서 발생하는 일반적인 예외"""

    def retry(operation):
        @wraps(operation)
        def wrapped(*args, **kwargs):
            last_raised = None
            RETRIES_LIMIT = 3
            for _ in range(RETRIES_LIMIT):
                try:
                    return operation(*args, **kwargs)
                except ControlledException as e:
                    logger.info("retrying %s", operation.__qualname__)
                    last_raised = e
            raise last_raise

    return wrapped


@retry
def run_operation(task):
    """실행 중 예외가 발생할 것으로 예상되는 특정 작업을 실행"""
    return task.run()

 

클래스 데코레이터

클래스 데코레이터의 장점

  • 코드 재사용의 이점을 공유함. 여러 클래스가 특정 인터페이스나 기준을 따르도록 강제할 수 있으며, 여러 클래스에 적용할 검사를 데코레이터에서 한 번만 하면 됨
  • 당장은 작고 간단한 클래스를 생성하고 나중에 데코레이터로 기능을 보강할 수 있음
  • 유지보수 시 데코레이터를 사용해 기존 로직을 훨씬 쉽게 변경 가능
from datetime import datetime

def hide_field(field) -> str:
    return "**민감한 정보 삭제**"

def format_time(field_timestamp: datetime) -> str:
    return field_timestamp.strftime("%Y-%m-%d %H:%M")

def show_original(event_field):
    return event_field

class EventSerializer:
    def __init__(self, serialization_fields: dict) -> None:
        self.serialization_fields = serialization_fields

    def serialize(self, event) -> dict:
        return {
            field: transformation(getattr(event, field))
            for field, transformation in
            self.serialization_fields.items()
        }

class Serialization:
    def __init__(self, **transformations):
        self.serializer = EventSerializer(transformation)
    
    def __call__(self, event_class):
        def serialize_method(event_instance):
            return self.serializer.serialize(event_instance)
        event_class.serialize = serialze_method
        return event_class

@Serialization(
    username=show_original,
    password=hide_field,
    ip=show_original,
    timestamp=format_time,
)

class LoginEvent:
    def __init__(self, username, password, ip, timestamp):
        self.username = username
        self.password = password
        self.ip = ip
        self.timestamp = timestamp
from dataclasses import dataclass
from datetime import datetime

@Serialization(
    username=show_original,
    password=hide_field,
    ip=show_original,
    timestamp=format_time,
)
@dataclass
class LoginEvent:
    username: str
    password: str
    ip: str
    timestamp: datetime

 

기타

데코레이터를 좀 더 구체적이고 제한적인 책임을 지닌 더 작은 데코레이터로 분류한다면, 데코레이터가 적용되는 순서또한 중요하다

@measure_time
@log_execution
def operation():
   ...

 

 

참고: 파이썬 클린코드(2020)

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함