'Better way 45. 애트리뷰트를 리팩터링하는 대신 @property 를 사용하라' 정리
Series -
Contents
0. 들어가며
Effective Python 2nd 파이썬 코딩의 기술 (교보문고 링크)을 제대로 이해하고자 블로그에 정리합니다.
현재 위치
Note
<6. Metaclasses and Attributes>
Item 45: Consider @property Instead of Refactoring Attributes
Better way 45. 애트리뷰트를 리팩터링하는 대신 @property 를 사용하라
Item 45: Consider @property Instead of Refactoring Attributes
Better way 45. 애트리뷰트를 리팩터링하는 대신 @property 를 사용하라
1. 한 줄 요약 및 첨언
@property
를 사용해서 기존 애트리뷰트를 사용하는 코드는 그대로 사용하면서 새로운 기능을 부여할 수 있습니다.
인터페이스를 점차 개선해 나가는 과정에서 중간중간 필요한 기능을 제공하는 수단으로도 유용합니다.
2. 사용 예시
아래와 같은 클래스가 있습니다.
여기서 quota
사용 부분에 새로운 기능을 얹고 싶었던 상황이었습니다.
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})'
기존 quata
애트리뷰트를 대신하여 @property
를 사용합니다.
from datetime import datetime, timedelta
# Example 7
class Bucket: # NewBucket
def __init__(self, period):
self.period_delta = timedelta(seconds=period)
self.reset_time = datetime.now()
# self.quota = 0 # 기존 요거 대신에 @property 로 quota 제공
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})')
@property
def quota(self):
return self.max_quota - self.quota_consumed
@quota.setter
def quota(self, amount):
delta = self.max_quota - amount
if amount == 0:
# Quota being reset for a new period
self.quota_consumed = 0
self.max_quota = 0
elif delta < 0:
# Quota being filled for the new period
assert self.quota_consumed == 0
self.max_quota = amount
else:
# Quota being consumed during the period
assert self.max_quota >= self.quota_consumed
self.quota_consumed += delta
기존 클래스를 호출하던 코드는 그대로 사용 합니다.
# Example 2
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
# Example 3
def deduct(bucket, amount):
now = datetime.now()
if (now - bucket.reset_time) > bucket.period_delta:
return False # Bucket hasn't been filled this period
if bucket.quota - amount < 0:
return False # Bucket was filled, but not enough
bucket.quota -= amount
return True # Bucket had enough, quota consumed
사용 예시
# Example 10
bucket = NewBucket(60)
print('Initial', bucket) # Initial NewBucket(max_quota=0, quota_consumed=0)
fill(bucket, 100)
print('Filled', bucket) # Filled NewBucket(max_quota=100, quota_consumed=0)
if deduct(bucket, 99):
print('Had 99 quota') # Had 99 quota
else:
print('Not enough for 99 quota')
print('Now', bucket) # Now NewBucket(max_quota=100, quota_consumed=99)
if deduct(bucket, 3):
print('Had 3 quota')
else:
print('Not enough for 3 quota') # Not enough for 3 quota
print('Still', bucket) # Still NewBucket(max_quota=100, quota_consumed=99)
3. 기억해야 할 내용
책에서 챕터 마지막 부분에 적혀있는 내용입니다.
Tip
Use
@property
to give existing instance attributes new functionality.@property
를 사용해 기존 인스턴스 애트리뷰트에 새로운 기능을 제공할 수 있다.Tip
Make incremental progress toward better data models by using
@property
.@property
를 사용해 데이터 모델을 점진적으로 개선하라.Tip
Consider refactoring a class and all call sites when you find yourself using
@property
too heavily.@property
메서드를 너무 과하게 쓰고 있다면, 클래스와 클래스를 사용하는 모든 코드를 리팩터링하는 것을 고려하라.