파이썬 코딩의 기술

파이썬코딩의기술-BW45 : 애트리뷰트를 리팩터링하는 대신 @property를 사용하라

J-Chris 2023. 3. 21. 14:46

내장 @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 메서드를 너무 과하게 쓰고 있다면, 클래스와 클래스를 사용하는
모든 코드를 리팩터링하는 것을 고려하라.

 

느낀점: 코드 실행이 안된다. 왜 안되는지 알아보자..