클래스에 대한 파이썬 데코레이터 적용

파이썬에서 클래스에 데코레이터를 적용하면 클래스의 동작을 동적으로 수정하거나 확장할 수 있습니다. 다음은 클래스 데코레이터를 구현하는 여러 가지 방법과 예제입니다.

1. 클래스 직접 수정하기

데코레이터는 클래스 자체를 수정하여 메서드나 속성을 추가할 수 있습니다.

메서드 추가 예제

def attach_welcome_message(target_class):
    def welcome(self):
        print(f"{self.__class__.__name__} 인사말입니다!")
    target_class.welcome = welcome
    return target_class

@attach_welcome_message
class User:
    pass

u = User()
u.welcome()  # 출력: User 인사말입니다!

속성 추가 예제

def set_metadata(**attributes):
    def wrapper(cls):
        for key, value in attributes.items():
            setattr(cls, key, value)
        return cls
    return wrapper

@set_metadata(release="v1.0", author="Alice")
class Application:
    pass

print(Application.release)  # 출력: v1.0
print(Application.author)   # 출력: Alice

2. 서브클래싱으로 확장하기

원본 클래스를 변경하지 않고 새로운 기능을 추가하려면 상속을 활용할 수 있습니다.

인스턴스 생성 로깅 예제

def log_instance_creation(original_class):
    class EnhancedClass(original_class):
        def __init__(self, *args, **kwargs):
            print(f"{original_class.__name__} 객체 생성됨 - args: {args}")
            super().__init__(*args, **kwargs)
    return EnhancedClass

@log_instance_creation
class DataProcessor:
    def __init__(self, data):
        self.data = data

processor = DataProcessor([1, 2, 3])  # 출력: DataProcessor 객체 생성됨 - args: ([1, 2, 3],)
print(processor.data)                 # 출력: [1, 2, 3]

3. 매개변수화된 데코레이터

데코레이터에 매개변수를 전달하여 클래스 동작을 조정할 수 있습니다.

여러 속성 일괄 추가 예제

def inject_attributes(**fields):
    def decorator(cls):
        for name, value in fields.items():
            setattr(cls, name, value)
        return cls
    return decorator

@inject_attributes(version="3.0", developer="Bob")
class Module:
    pass

print(Module.version)    # 출력: 3.0
print(Module.developer)  # 출력: Bob

4. 싱글톤 패턴 구현

클래스가 오직 하나의 인스턴스만 갖도록 제한하는 데코레이터를 만들 수 있습니다.

__new__ 메서드 재정의 방식

def enforce_singleton(cls):
    instance_ref = [None]
    original_new = cls.__new__

    def custom_new(subclass, *args, **kwargs):
        if instance_ref[0] is None:
            instance_ref[0] = original_new(subclass) if original_new != object.__new__ else original_new(subclass)
        return instance_ref[0]

    cls.__new__ = staticmethod(custom_new)
    cls.__init__ = lambda self, *a, **kw: None  # 초기화 중복 방지
    return cls

@enforce_singleton
class UniqueService:
    def __init__(self, identifier):
        self.identifier = identifier

first = UniqueService("ID1")
second = UniqueService("ID2")
print(first is second)      # 출력: True
# print(first.identifier)   # AttributeError 발생 (초기화 무시됨)

5. 클래스 등록 시스템

전역 저장소에 클래스를 자동 등록하여 나중에 접근할 수 있도록 합니다.

딕셔너리에 클래스 등록 예제

registered_classes = {}

def register_class(alias):
    def decorator(cls):
        registered_classes[alias] = cls
        return cls
    return decorator

@register_class('data_handler')
class Handler:
    pass

print(registered_classes['data_handler'])  # 출력: <class '__main__.Handler'>

주의사항

  • 부작용 관리: 클래스를 직접 수정하면 다른 코드에 영향을 줄 수 있으므로, 가능하면 상속을 사용하세요.
  • 생성자 호환성: 상속 기반 확장을 할 때 부모 클래스의 __init__ 메서드와 인수를 잘 맞춰야 합니다.
  • 메타클래스 충돌: 이미 메타클래스를 사용 중인 클래스에는 특별히 주의해야 합니다.

적절하게 설계된 클래스 데코레이터는 원본 소스 코드를 변경하지 않고도 클래스의 기능을 유연하게 확장할 수 있게 해줍니다. 이는 개방-폐쇄 원칙(OCP)을 따르는 좋은 예시입니다.

태그: python decorator class-decorators singleton-pattern OOP

5월 27일 10:03에 게시됨