본문 바로가기

프로그래머/Python

[윤성우의 열혈 파이썬 중급편] 30. property

출처 : 윤성우의 열혈 파이썬 : 중급

30. property

안전하게 접근하기

# natural.py
class Natural:
    def __init__(self, n):
        if(n < 1):
            self.__n = 1
        else:
            self.__n = n
    def getn(self):
        return self.__n
    def setn(self, n):
        if(n < 1):
            self.__n = 1
        else:
            self.__n = n

def main():
    n = Natural(-3)
    print(n.getn())
    n.setn(2)
    print(n.getn())

main()

# natural2.py
class Natural:
    def __init__(self, n):
        self.setn(n)
    def getn(self):
        return self.__n
    def setn(self, n):
        if(n < 1):
            self.__n = 1
        else:
            self.__n = n

def main():
    n1 = Natural(1)
    n2 = Natural(2)
    n3 = Natural(3)
    n1.setn(n2.getn() + n3.getn())
    print(n1.getn())

main()

# natural3.py
class Natural:
    def __init__(self, n):
        self.setn(n)
    def getn(self):
        return self.__n
    def setn(self, n):
        if(n < 1):
            self.__n = 1
        else:
            self.__n = n
    n = property(getn, setn)

def main():
    n1 = Natural(1)
    n2 = Natural(2)
    n3 = Natural(3)
    n1.n = n2.n + n3.n
    print(n1.n)

main()
  • 프로퍼티 설정
    • 속성(변수) n의 값을 '참조'하는 경우에는 getn을 호출해서 반환되는 값을 전달하겠다
    • 속성(변수) n의 값을 '저장'하는 경우에는 setn을 호출하면서 그 값을 전달하겠다
  • 프로퍼티를 설정하면 안정성은 유지되고 더불어 작성하는 문장도 간결해지는 장점이 있다

property

# natural4.py
class Natural:
    def __init__(self, n):
        self.setn(n)
    n = property()
    def getn(self):
        return self.__n
    n = n.getter(getn)
    def setn(self, n):
        if(n < 1):
            self.__n = 1
        else:
            self.__n = n
    n = n.setter(setn)

def main():
    n1 = Natural(1)
    n2 = Natural(2)
    n3 = Natural(3)
    n1.n = n2.n + n3.n
    print(n1.n)

main()
  • property 객체의 생성으로 이어진다
  • property 객체를 생성하면서 getn과 setn 메소드를 등록한 것이다
  • property 객체의 생성과 getn 및 setn 메소드의 등록을 별도의 문장에서 각각 진행할 수도 있다
  • getter 또는 setter 메소드 호출 시 반환되는 객체를 변수에 저장하는 일을 잊지 말아야 한다
# natural5.py
class Natural:
    def __init__(self, n):
        self.setn(n)
    n = property()
    def pm(self):
        return self.__n
    n = n.getter(getn)
    def pm(self, n):
        if(n < 1):
            self.__n = 1
        else:
            self.__n = n
    n = n.setter(pm)

def main():
    n1 = Natural(1)
    n2 = Natural(2)
    n3 = Natural(3)
    n1.n = n2.n + n3.n
    print(n1.n)

main()
  • 프로프티를 등록하고 나면 사실상 getn이나 setn과 같은 이름은 사용할 이유가 없어진다
    • 따라서 프로퍼티에 등록할 메소드의 이름을 동일하게 두는 경우도 있다
  • 프로퍼티를 설정한 후에는 한 가지 방법으로만 변수에 접근하여 혼란을 줄일 필요가 있다
    • 즉 메소드의 이름을 통해 변수에 접근하는 일을 피해야 한다
    • 따라서 프로퍼티에 등록할 게터와 세터의 이름을 동일하게 두는 경우가 매우 흔하다

또 다른 방식 - 데코레이터

# natural6.py
class Natural:
    def __init__(self, n):
        self.n = n
    @property
    def n(self):
        return self.__n
    @n.setter
    def n(self, n):
        if(n < 1):
            self.__n = 1
        else:
            self.__n = n

def main():
    n1 = Natural(1)
    n2 = Natural(2)
    n3 = Natural(3)
    n1.n = n2.n + n3.n
    print(n1.n)

main()
  • 간결하여 더 많이 쓰인다
  • @properrty 선언의 결과는
    • property 객체를 생성하면서 이어서 등장하는 메소드를 게터로 지정
    • 이렇게 생성된 property 객체를 메소드 이름인 n에 저장
  • @n.setter 선언의 결과는
    • 이어서 등장하는 메소드를 n에 저장된 property 객체의 세터로 등록
    • 이렇게 생성된 property 객체를 메소드 이름인 n에 저장