2. 내 손으로 만드는 데코레이터 공장

파이썬에서 친절하게 기본으로 제공하는 @property 라는 데코레이터를 이용해 멋진 보안 문지기를 만들었죠? 그렇다면 이 property 는 속이 어떻게 생겼길래 이런 마법을 부리는 걸까요? 우리가 직접 그 내부와 쏙 빼닮은 나만의 “수제 프로퍼티 클래스”를 만들어보면서 원리를 뜯어보겠습니다.

2.1 커스텀 Property 클래스의 구조

파이썬의 property는 사실 함수가 아니라 거대한 통제실 클래스입니다. 이 통제실 안에는 데이터를 읽고(fget), 쓰고(fset), 지우는(fdel) 3명의 요원이 대기하고 있습니다.

이 원리를 따라 우리만의 통제실 MyProperty 인스턴스를 직접 만들어 보면 이렇습니다.

class MyProperty:
    # 3명의 요원(함수)을 초기에 등록받는 역할을 합니다.
    def __init__(self, fget=None, fset=None, fdel=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel

    # '읽기' 명령이 들어왔을 때 fget 요원 출동!
    def __get__(self, obj, objtype=None):
        if self.fget is None:
            raise AttributeError("읽을 수 없는 속성입니다.")
        return self.fget(obj)

    # '쓰기' 명령이 들어왔을 때 fset 요원 출동!
    def __set__(self, obj, value):
        if self.fset is None:
            raise AttributeError("변경할 수 없는 속성입니다.")
        self.fset(obj, value)

    # '지우기' 명령이 들어왔을 때 fdel 요원 출동!
    def __delete__(self, obj):
        if self.fdel is None:
            raise AttributeError("지울 수 없는 속성입니다.")
        self.fdel(obj)

이 코드가 바로 파이썬에 내장되어 있는 property 클래스의 아주 단순화된 핵심 심장부입니다. 이 통제실의 핵심은 바로 __get__, __set__, __delete__ 라는 파이썬 고유의 마법 주문(스페셜 메서드)들에 있습니다.


2.2 데코레이터를 등록해주는 도구 만들기

여기에, 내장 @property 처럼 우리도 함수 바로 위에 @내이름.setter를 붙일 수 있도록 데코레이터 지원 파트를 마저 붙여주는 것이 좋습니다.

class MyProperty:
    # (앞선 __init__, __get__, __set__ 생략...)
    
    # 누군가 @이름.setter 데코레이터를 쓸 수 있게 열어주기!
    def setter(self, fset_func):
        print(">> 새 setter 요원 등록 완료!")
        # 기존 요원들(fget, fdel)은 살려두고, 
        # 새로운 쓰기 요원(fset_func)을 장착한 MyProperty 기계를 새로 복사해서 줍니다.
        return type(self)(self.fget, fset_func, self.fdel)

    # 누군가 @이름.getter 데코레이터를 쓸 수 있게 열어주기!
    def getter(self, fget_func):
        return type(self)(fget_func, self.fset, self.fdel)

이처럼 프로퍼티란, 파이썬이 던져주는 3가지 특별한 스위치(__get__, __set__, __delete__)가 장착된 리모컨 객체(=디스크립터)를 변수 이름에 씌워놓은 것에 불과합니다. 이제 대망의 ‘디스크립터(Descriptor)’가 무엇인지 다음 장에서 더 깊이 알아보겠습니다!

서브목차