반응형

Intro


안녕하세요, 지난글에서는 python의 decorator에 대해서 간단히 살펴봤습니다.
이번 글에서는 python에서 기본으로 제공해주면서 많이 쓰이는 @property decorator에 대해서 정리하겠습니다.

@property


@property decorator는 많은 분들이 private 변수의 getter, setter를 설정하기 위해서 많이 사용한다고 해서, 그 용도로만 쓰이는 건줄 알았습니다. 하지만 조금 더 알아본 결과, 제가 생각하는 @property decorator의 본질은 "function(함수)을 variable(변수)처럼 사용하기" 입니다.

예를 들면 아래와 같습니다.

class PropertyTest():
    @property
    def func_with_property(self):
        print("called with property")

    def func_without_property(self):
        print("called without property")

if __name__ == "__main__":
    pt = PropertyTest()

    tc.func_with_property
    ## output: called with property

    tc.func_without_property
    ## output: <bound method PropertyTest.func_without_property of <__main__.PropertyTestClass object at 0x0000016FC1D827F0>>

    tc.tc.func_without_property()
    ## output: called without property

위의 예시를 보시면, @property 를 위에 적은 func_with_property를 호출할 때는 ()를 안붙여도 그 반환값을 알 수 있습니다.
이러한 특성을 활용해서 private 변수의 getter, setter를 설정할 수 있는 겁니다.

우선 python에서도 private 변수를 설정할 수 있는 걸 모르는 분이 있을 수 있는데요, 변수이름 앞에 __ 또는 _를 붙여서 외부로부터 접근을 제어할 수 있습니다. 그래서 private 변수에 접근하기 위한 getter와 setter가 필요한 것이죠.

python의 private 변수와 관련한 내용은 따로 다루도록 하겠습니다.

먼저 일반적인 getter, setter를 이용한 private 변수와 public 변수로의 접근을 비교해보겠습니다.

class GetterSetterWithFunc():
    def __init__(self, pri_var, pub_var):
        self.__pri_var = pri_var
        self.pub_var = pub_var

    def get_pri_var(self):
        return self.__pri_var

    def set_pri_var(self, pri_var):
        self.__pri_var = pri_var

if __name__ == "__main__":
    gswf = GetterSetterWithFunc(1, 10)

    gswf.__pri_var
    ## output: AttributeError

    gswf.pri_var
    ## output: AttributeError

    gswf.get_pri_var()
    ## output: 1

    gswf.set_pri_var(100)
    gswf.get_pri_var()
    ## output: 100

    gswf.pub_var
    ## output: 10

    gswf.pub_var = 1000
    gswf.pub_var
    ## output: 1000

위의 예시와 같이, private 변수인 pri_varget_pri_var()set_pri_var()을 통해서만 접근이 가능한 반면, public 변수인 pub_var은 바로 접근이 가능합니다.

그런데, private 변수와 public 변수를 다룰 때 이를 구분해서 사용하기 불편하기도 하죠, @property decorator를 사용하면 private, public상관없이 다룰 수 있습니다. 어떻게 달라지는지 보겠습니다.

class GetterSetterWithProperty():
    def __init__(self, pri_var, pub_var):
        self.pri_var = pri_var
        self.pub_var = pub_var

    @property
    def pri_var(self):
        return self.__pri_var

    @pri_var.setter
    def pri_var(self, pri_var):
        self.__pri_var = pri_var

if __name__ == "__main__":
    gswp = GetterSetterWithProperty(1, 10)

    gswp.pri_var
    ## output: 1

    gswp.pri_var = 100
    gswp.pri_var
    ## output: 100

    gswp.pub_var
    ## output: 10

    gswp.pub_var = 1000
    gswp.pub_var
    ## output: 1000

이와 같이, @property를 사용하면 private, public 변수를 같은 방법으로 다룰 수 있게 됩니다. 다만 차이점이 있다면, __init__()에서 호출되는 self.pri_var는 변수가 아닌 아래에 정의된 pri_var function이고, private 변수인 pri_var는 해당 function을 실행할 때 생성 됩니다. 반면 pub_var__init__()에서 바로 생성됩니다.

마무리


오늘은 python의 기본 decorator 중 하나인 @property decorator에 대해서 정리해봤습니다. 다음 글에서는 @staticmethod, @classmethod에 대해서 정리하겠습니다.

글 읽어주셔서 감사합니다!

반응형

+ Recent posts