Post

[Py: Class] 8.Property


안전하게 접근하면서 간결하게…?

  • 이전 포스팅에서 클래스 속성의 접근 방식은
    직접 접근 방법보다 메서드를 이용한 간접 접근 방식이 안전하다는 것에 관한 내용을 다루었다.


  • 그리고, 이러한 보호를 위한 메서드는 속성을 다루는 성격에 따라 다음과 같이 구분할 수 있다.
    • getter: 클래스 객체의 값을 조회하는 성격을 가진 메서드
    • setter: 클래스 객체의 값을 수정하는 성격을 가진 메서드


  • 예를 들어, 다음 코드의 getn은 값을 반환(=조회)함으로 getter에 해당하며,
    setn은 클래스 속성을 수정하기 때문에 setter에 해당한다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
      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
    


  • 메소드를 이용한 간접 접근 방식 자체는 안전하지만,
    명시적인 메소드 호출이 빈번해질 경우 코드의 복잡성을 유발할 수 있다.
    이를 위해 안전성을 확보하면서 코드를 더 간결하게 표현할 수 있는 property를 사용하는 방법이 존재한다.



Property

(1) property() 함수란?

  • property는 파이썬의 내장 함수인 property()를 사용하여 생성할 수 있다.
    1
    
      property(fget=None, fset=None)
    
    • fget
      • 객체의 속성을 조회하는 함수가 위치한다.
      • 프로퍼티가 우변항에 위치할 떄, fget에 위치한 함수가 호출된다.
      • 예를 들어, k = [class 객체].[property 속성]를 수행하면 변수 k에 조회된 class 객체의 지정된 속성 값을 저장한다.
    • fset
      • 객체의 속성을 수정하는 함수가 위치한다.
      • 프로퍼티가 좌변항에 위치할 때, fset에 위치한 함수가 호출된다.
      • 예를 들어, [class 객체].[property 속성] = 20을 수행하면 정수 20이 class 객체의 지정된 속성 값에 저장된다.
    • 그 외, 삭제를 위한 fdel인자와 프로퍼티 설명을 위한 doc인자가 존재한다.


  • 다음은 property를 사용하여 작성한 코드이다. 주석 처리된 명시적인 메소드 호출보다 상대적으로 간결해짐을 확인할 수 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
      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
        
          p = property(getn, setn) # property 설정
        
      def main():
          n1 = natural(1)
          n2 = natural(2)
          n3 = natural(3)
          # n1.setn(n2.getn()+n3.getn())
          n1.p = n2.p + n3.p
          print(n1.p)
        
      main()
    


(2) property() 함수의 메소드 등록법

  • p = property(fget, fset) 코드 수행 시,
    property 객체가 생성되는 동시에 getter와 setter 등록도 동시에 진행된다.


  • 하지만, 이를 동시에 진행하지 않고 빈 property객체의 gettersetter 메소드를 이용하여 함수를 개별로 등록할 수 있다.
    • property.getter 메소드: getter가 등록된 새로운 property 객체를 생성 및 반환 (기존 fset 유지)
    • property.setter 메소드: setter가 등록된 새로운 property 객체를 생성 및 반환 (기존 fget 유)


  • 다음은 getter와 setter를 개별로 등록하는 예시 코드이다. 코드에서 getter와 setter가 같은 이름으로 작성된 것을 확인할 수 있는데, 이는 프로퍼티를 통해서 getter와 setter를 구분하여 사용할 수 있으므로 굳이 이름으로 구분할 필요가 없기 때문이다. 종종 이렇게 사용한다는데, 내 성격상 나는 이렇게 하지는 않을 것 같다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    class natural:  
        def __init__(self, n):
            self.setn(n)
        p = property() # property객체 생성
        
      
        def pm(self):
            return self.__n
        p = p.getter(getn) # 위의 pm메소드를 getter로 등록  
      
        def pm(self, n):
            if(n < 1):
                self.__n = 1
            else:
                self.__n = n
        p = p.setter(setn) # 위의 pm메소드를 setter로 등록
    



내장 @property 데코레이터

  • 위 방식보다 @property라는 내장 데코레이터의(Decorator)를 이용해서 더 쉽게 프로퍼티를 정의할 수 있다.


  • 다음은 위의 예제를 @property를 이용해 재구성한 코드이다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    class natural:  
        def __init__(self, n):
            self.setn(n)
        
        @property # property를 생성하면서 하단의 메소드를 getter로 지정
        def pm(self):
            return self.__n
            
        @pm.setter # 위에서 생성한 property에 하단의 메소드를 setter로 지정
        def pm(self, n):
            if(n < 1):
                self.__n = 1
            else:
                self.__n = n
    



References

This post is licensed under CC BY 4.0 by the author.