파이썬코딩의기술-BW45 : 애트리뷰트를 리팩터링하는 대신 @property를 사용하라
내장 @property 데코레이터를 사용하면, 겉으로는 단순한 애트리뷰트처럼 보이지만,
실제로는 지능적인 로직을 수행하는 애트리뷰트를 정의할 수 있다.
@property의 고급 활용법
- 간단한 수치 애트리뷰트를 그때그때 요청에 따라 계산해 제공하도록 바꾸는 것을 들 수 있다.
이 기법은 기존 클래스를 호출하는 코드를 전혀 바꾸지 않고도 클래스 애트리뷰트의 기존 동작을 변경할 수 있기 때문에
아주 유용하다.
- 인터페이스를 점차 개선해나가는 과정에서 중간중간 필요한 기능을 제공하는 수단으로도 유용하다.
from datetime import datetime, timedelta
class Bucket:
def __init__(self, period):
self.period_delta = timedelta(seconds = period)
self.reset_time = datetime.now()
self.quota = 0
def __repr__(self):
return f'Bucket(quota={self.quota})'
리키 버킷 알고리즘은 시간을 일정한 간격으로 구분하고(이를 주기라고 부름),
가용 용량을 소비할 때마다 시간을 검사해서 주기가 달라질 경우에는 이전 주기에 미사용한 가용 용량이
새로운 주기로 넘어오지 못하게 막는다.
def fill(bucket, amount):
now = datetime.now()
if (now - bucket.reset_time) > bucket.period_delta:
bucket.quota = 0
bucket.reset_time = now
bucket.quota += amount
가용 용량을 소비하는 쪽에서는 어떤 작업을 하고 싶을 때마다 먼저 리키 버킷으로부터
자신의 작업에 필요한 용량을 할당받아야 한다.
def deduct(bucket, amount):
now = datetime.now()
if (now - bucket.reset_time) > bucket.period_delta:
return False # 새주기가 시작됐는데 아직 버킷 할당량이 재설정되지 않았다
if bucket.quota - amount < 0:
return False # 버킷의 가용 용량이 충분하지 못하다
else:
bucket.quota -= amount
return true # 버킷의 가용 용량이 충분하므로 필요한 분량을 사용한다
이 클래스를 사용하려면 먼저 버킷에 가용 용량을 미리 정해진 할당량만큼 채워야한다
bucket = Bucket(60)
fill(bucket, 100)
print(bucket)
그 후 사용할 때마다 필요한 용량을 버킷에서 빼야한다.
if deduct(bucket, 99):
print('99 용량 사용')
else:
print('가용 용량이 작아서 99 용량을 처리할 수 없음')
print(bucket)
어느 순간이 되면, 버킷에 들어 있는 가용 용량이 데이터 처리에 필요한 용량보다
작아지면서 더이상 작업을 진행하지 못하게 된다. 이런 경우 버킷의 가용 용량 수준은
변하지 않는다.
if deduct(bucket, 3):
print('3 용량 사용')
else:
print('가용 용량이 작아서 3 용량을 처리할 수 없음')
@property를 사용하면 데이터 모델을 점진적으로 개선할 수 있으므로
@property를 선호한다.
- Bucket 예제를 살펴보면, 처음에는 fill과 deduct 함수를 인스턴스 메서드로
만들어야 한다고 생각할 수도 있다.
- 그 생각이 맞을 수도 있지만, 객체가 처음부터 제대로 인터페이스를
제공하지 않거나 아무 기능도 없는 데이터 컨테이너 역할만 하는 경우가 실전에서는
자주 발생한다.
@property는 실제 세계에서 마주치는 문제를 해결할 떄 도움이된다.
하지만 @property를 과용하지는 말라.
여러분이 @property 메서드를 반복해서 확장해나가고 있다면,
이제는 설계한 코드의 단점을 포장하려고 계속 노력하는 대신 작성한 클래스를
리팩터링해야 할 때다.
### 기억해야 할 내용 ###
- @property를 사용해 기존 인스턴스 애트리뷰트에 새로운 기능을 제공할 수 있다.
- @property를 사용해 데이터 모델을 점진적으로 개선하라.
- @property 메서드를 너무 과하게 쓰고 있다면, 클래스와 클래스를 사용하는
모든 코드를 리팩터링하는 것을 고려하라.
느낀점: 코드 실행이 안된다. 왜 안되는지 알아보자..