2 minute read

본 포스팅은 “윤성우의 열혈 파이썬 중급편” 책 내용을 기반으로 작성되었습니다. 잘못된 내용이 있을 경우 지적해 주시면 감사드리겠습니다.

22-1. 안전하게 접근하기

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()
(결과) 1
       2

위 코드에서 getn 함수는 값 꺼내는 역할, setn 함수는 값 수정하는 역할을 한다.
위와 같이 코드를 짤 경우, 잦은 메소드 호출로 코드가 복잡해 보일 수 있다. 다음 예제 처럼 말이다.

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()
(결과) 5

메소드가 자주 호출되어서 자칫하면 헷갈릴 수 있을 것 같다. 어떻게 이를 간단해 보이도록 만들 수 있을까? 이때 프로퍼티를 이용해보자!

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()
(결과) 5

n = property(getn, setn) 을 프로퍼티 설정 이라고 한다. 이 코드는 속성 n의 값을 참조하는 경우 getn을 호출해서 반환되는 값을 전달하고, 속성 n에 값을 저장하는 경우에는 setn을 호출하여 그 값을 전달한다! 라는 의미를 갖는다. 이 코드는 property 객체의 생성으로 이어진다!

22-2. property

다음과 같이 property 객체 생성과 함께 getn과 setn 메소드 등록을 별도의 문장으로 진행할 수 있다.

class Natural:
  def __init__(self, n):
    self.setn(n)
  n = property() 
  def getn(self):
    return self.__n
  n = n.getter(getn)  # getter 등록된 새 property 객체 생성 및 반환
  def setn(self, n):
    if(n<1):
      self.__n = 1
    else:
      self.__n = n
  n = n.setter(setn)  # setter 등록된 새 property 객체 생성 및 반환
  

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

main()
(결과) 5

다음과 같이 프로퍼티에 등록할 메소드 이름을 동일하게 둘 수도 있다.

class Natural:
  def __init__(self, n):
    self.n = n
  def pm(self):
    return self.__n
  n = property(pm)
  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()
(결과) 5

22-3. 또 다른 방식

데코레이터 라는 녀석을 기반으로 프로퍼티를 지정할 수 있다. 가장 간결한 방법인데, 데코레이터에 대한 설명은 다음에 설명을 하도록 한다. 예제 부터 보자.

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()
(결과) 5

코드 별로 확인해보자.

@property
def n(self):
  return self.__n

요 부분은 property 객체를 생성하면서 바로 다음에 등장하는 메소드를 getter로 지정한다. 그리고 이 property 객체를 n에 저장한다! 즉 다음 코드와 동일하다 볼 수 있다.

def n(self):
  return self.__n
n = property(n)

사실 위 코드는 말이 좀 안된다(실제 적용해보면 에러남. 메소드 n에 객체를 저장하다니?). 아무래도 데코레이터 개념을 익혀야 이해할 수 있을 것 같다.

그 다음 코드를 보자.

@n.setter
def n(self, n):
  if(n<1):
    self.__n = 1
  else:
    self.__n = n

이 부분은 다음 등장하는 메소드를 n 저장된 property 객체의 setter에 등록하며, 이 property 객체를 n에 저장한다. 즉 다음 코드와 동일하다.

def n(self, n):
  if(n<1):
    self.__n = 1
  else:
    self.__n = n
n = n.setter(n)

Leave a comment