지능적인 로직을 수행하는 애트리뷰트 정의가 가능
요청에 맞게 애트리뷰트를 바꿀 수 있다.
클래스의 내 코드를 바꾸지 않고 동작 변경이 가능
#leaky bucket 흐름 제어 알고리즘
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 # 버킷의 가용 용량이 충분하므로 필요한 분량 사용
위의 구현 문제는 버킷 시작 시 가용 용량이 얼마인지 알 수 없다는 점이다.
#주기에 재설정된 가용 용량인 MAX_quota와 소비한 용량의 합계인 quota_consumed 추적
class NewBucket:
def __init__(self, period):
self.period_delta = timedelta(seconds = period)
self.reset_time = datetime.now()
self.max_quota = 0
self.quota_consumed = 0
def __repr__(self):
return (f'NewBucket(max_quota={self.max_quota}), '
f'quota_consumed = {self.quota_consumed})')
#fill 과 deduct함수가 quota 매트리뷰트에 값을 할당할 시 NewBucket 클래스의 혀냊 사용 방식
@property
def quota(self):
return self.max_quota - self.quota_consumed
@property를 사용해서 기존 인스턴스 애트리뷰트에 새로운 기능 제공
@property를 사용해서 데이터 모델을 점진적으로 개선
@property 메서드를 너무 과하게 쓰고 있다면, 클래스와 클래스를 사용하는 모든 코드 리팩터링