Skip to content

Python:ProxyProperties

클래스 속성을 메서드와 속성 모두로 사용할 수 있다는 사실, 알고 계셨나요?!?

이는 Python의 기본 기능은 아니지만, Python의 마법 같은 메서드와 설명자를 효과적으로 활용하여 무엇을 할 수 있는지 보여주는 예시입니다.

Code

from typing import Callable, Generic, TypeVar, ParamSpec, Self

P = ParamSpec("P")
R = TypeVar("R")
T = TypeVar("T")

class ProxyProperty(Generic[P, R]):
    func: Callable[P, R]
    instance: object

    def __init__(self, func: Callable[P, R]) -> None:
        self.func = func

    def __get__(self, instance: object, _=None) -> Self:
        self.instance = instance
        return self

    def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R:
        return self.func(self.instance, *args, **kwargs)

    def __repr__(self) -> str:
        return self.func(self.instance)

def proxy_property(func: Callable[P, R]) -> ProxyProperty[P, R]:
    return ProxyProperty(func)

class Container:
    @proxy_property
    def value(self, val: int = 5) -> str:
        return f"The value is: {val}"

# Example usage
c = Container()
print(c.value)      # Returns: The value is: 5
print(c.value(7))   # Returns: The value is: 7

이 기능은 어떻게 작동할까요? 파이썬의 설명자 프로토콜(Descriptor Protocol)1 에 따라 작동합니다 .

  1. The __get__ method transforms the ProxyProperty object into a descriptor.
  2. When you access c.value, Python calls __get__ which returns self (the descriptor instance).
  3. The __repr__ method handles property access (returning default values).
  4. The __call__ method handles method calls with parameters.

이렇게 하면 직접 읽을 수도 있고 함수처럼 호출할 수도 있는 이중 용도의 속성이 생성됩니다!

이 클래스의 장점은 속성에 구성이 필요하거나 합리적인 기본값을 가져야 하지만 여전히 사용자 정의가 가능한 직관적인 API를 만들 수 있다는 것입니다.

See also

Favorite site

References


  1. https://docs.python.org/3/howto/descriptor.html 

  2. 14_Advanced_Python_Features_-_Edward_Li's_Blog.pdf