무효 클릭 IP 추적 중...
파이썬/파이썬 중급

[파이썬 중급] @property, @함수명.setter 사용법

꼬예 2021. 7. 23.

이번 포스팅에서는 클래스 METHOD 위에 DECORATOR 형태로 자주 등장하는 @property, @함수명.setter 에 대해서 알아보도록 하겠습니다.

 

 

private variable 사용

class Rectangle:
  def __init__(self,width, height):
    self.width = width
    self.height = height

  def area(self):
    return self.width * self.height

  def __repr__(self):
    return 'Rectangle({0}, {1})'.format(self.width, self.height)
    
  r1 = Rectangle(10, 20)
  r1

output :

우선 간단한 클래스를 구현해보았습니다.  넓이 10,  높이 20 으로 이루어진 사각형을 만들기 위한 클래스 인데요.

 

 

클래스 특성상 아래와  같이 코드를 작성하면 초기 width값이 바로 변경이 됩니다. 

r1.width = 30 
r1

output :

파이썬에서는 객체명.width, 즉 해당 property에 직접 접근하여 값을 바꾸는것을 좋아하지 않습니다. 

때때로 해당정보가 바뀌면 안되는 중요한 정보일 수도 있으니까요.

 

 

파이썬 이러한 것을 최소한으로 지키기 위해 아래와 같이 코드형식으로 작성하는데요.

 

달라진 부분을 눈치채셨나요?

class Rectangle:
  def __init__(self,width, height):
    self._width = width
    self._height = height

  def area(self):
    return self.width * self.height

  def __repr__(self):
    return 'Rectangle({0}, {1})'.format(self.width, self.height
    
r1 = Rectangle(10, 20)
r1.width = 30
r1

 self._width, self._height와 같이 언더바를 붙힌 형태의 변수를 만들어줍니다. 우리는 이러한 variable을 private variable이라고 부릅니다 이름에서도 느낄 수 있듯이 은밀한 느낌이들죠.

 

물론 이러한 형태로 바꾸었다고 값을 변경 할수 없는 건 아닙니다. r1._width로 접근하면 똑같이 값이 바뀝니다.

일종의 개발자들끼리의 약속이라 보시면 될것 같습니다.

 

처음 접근했던 방식으로 r1.width 로 접근하면 당연히 해당 property명이 _width로 바뀌었기 때문에 오류가 납니다. 

앞서 제가 최소한의 방어장치라고 표현한 부분이 바로 이러한 부분에 해당합니다.

output :

 

자! 그렇다면 필요에 의해 private valuable값을 바꿀 필요가 있을때 어떡할까요?

이때는 method를 통해 접근을 해야합니다.

 

method를 통한 값 변경

class Rectangle:
  def __init__(self,width, height):
    self._width = width
    self._height = height

  def get_width(self):
    return self._width

  def set_width(self, width):
    if width <= 0:
      raise ValueError('Width must be positive.')
    else:
      self._width = width

  def get_height(self):
    return self._height

  def set_height(self, height):
    if height <= 0:
      raise ValueError('Height must be positive.')
    else:
      self._height = height

  def area(self):
    return self.width * self.height

  def __repr__(self):
    return 'Rectangle({0}, {1})'.format(self.width, self.height)
    
r1 = Rectangle(10, 20)
r1.set_height(-5)

 

총 4개의  method 들을 추가했습니다.

보시면 아시겠지만 get_width , set_width , get_height, set_height입니다.

 set_함수는 당연히 새로운 값을 지정하는것이기 때문에 인자로 width,height를 받을 자리를 만들어 놓았습니다. 

 

이렇게 메소드 형태로 값을 불러오면 좋은점은 특정 조건에 해당하는 값을 set할수 있다는 점입니다.

우리가 인자로 받는 값은 길이와 높이기 때문에, 이값은 당연히 양수여야겠죠?

 

그래서 위와 같은 조건을 통해, 조건에 해당하지 않으면 ValueErorr을 리턴하는 식의코드를 추가했습니다. 

 

 

output을 보면 실제로 정상적으로 작동 되는 걸 알 수 있습니다.

output :

여기까지 포스팅을 읽으신분 들은 그럼 @porperty, @함수.setter은 언제쓰는지 궁금하실것같은데요..

사실 위에서 구현한 기능을 메소드가 아닌 property 형태로 사용할 수있는 것이 바로 위 데코레이터의 기능입니다. 

사실 단순히 값을 불러오는데 메소드를 쓰는건 우리 직관에 어긋나죠.

이때 데코레이터를 사용하면 메소드를 이용할때의 장점도 함께 가져갈 수 있습니다. 

 

무슨 얘긴지는 코드를 통해 살펴보겠습니다.

 

데코레이터 적용

class Rectangle:
  def __init__(self,width, height):
    self._width = width
    self._height = height

  @property
  def width(self):
    return self._width

  @width.setter
  def width(self, width):
    print('setter가 실행되었습니다.')
    if width <= 0:
      raise ValueError('Width must be positive.')
    else:
      self._width = width

  @property
  def height(self):
    return self._height

  @height.setter
  def height(self, height):
    if height <= 0:
      raise ValueError('Height must be positive.')
    else:
      self._height = height

  def area(self):
    return self.width * self.height

  def __repr__(self):
      return 'Rectangle({0}, {1})'.format(self.width, self.height)

 

데코레이터를 이용해서 코드를 바꿔보았습니다.

우선 get_width같은 method스러운 변수명을 property스럽게 변경을 하였고 그 위에 데코레이터를 올려주었는데요

 

@property는 값을 그냥 불러오는 기능을 하는 함수 위에 적었고, @함수명.setter은 값을 재지정해주는 기능을 하는 함수 위에 적었습니다. 

(참고로 def height(self) 함수와 def height(self,height) 함수는 이름이 같다고해서 한쪽이 한쪽을 덮어쓰는 override 현상이 일어나지 않습니다.  엄연히 인자를 하나 더 받기 때문에 다른 형태입니다.)

 

실제로 어떻게 동작하는지 볼까요?

r1 = Rectangle(10, 20) 
r1.width = 5
r1

output :

설명을 위해 width함수 안에 print문을 추가하였는데요.

분명 method인것같은데 데코레이터를 추가했다는 이유로 property 같이 작동하는 것을 볼 수가 있죠.

 

r1.width

output :

값을 불러오는 method도 @property를 통해 위와 같이 동작을 합니다. 

  • 트위터 공유하기
  • 페이스북 공유하기
  • 카카오톡 공유하기
이 컨텐츠가 마음에 드셨다면 커피 한잔(후원) ☕

댓글