▶︎ functools.cached_property
파이썬 3.8
버전부터 __dict__
를 활용한 cached_property
기능이 추가되었다.
특정 property
를 캐싱할 수 있는 기능인데, 이를 이용하면 속성에 처음 접근할 때 계산을 수행하고, 이후에는 동일한 값을 반환하여 성능을 향상 시킬 수 있다.
cached_property
기능의 경우 주로 클래스의 인스턴스 속성이나, 메서드의 결과를 캐시할 때 매우 유용하다.
‣ 예제
아래의 첫 번째 예시는 연산이 오래 걸리는 property를 다시 계산하지 않고 재사용하기 위해 cached_property
를 도입해본 예시이다.
from functools import cached_property
class Example:
def __init__(self, peoples: list[dict[str, str|int]]) -> None:
self.peoples = peoples
@cached_property
def average_age(self):
print("나이 평균 계산 중...")
total_age = sum(person['age'] for person in self.peoples)
return total_age / len(self.peoples)
# 사용 예시
people_data = [
{'name': 'Alice', 'age': 30},
{'name': 'Bob', 'age': 25},
{'name': 'Charlie', 'age': 35}
]
# 인스턴스 생성
example_instance = Example(people_data)
# 처음 average_age에 접근하면 계산이 수행됨
print(example_instance.average_age) # 출력: 나이 평균 계산 중... 30.0
# 두 번째부터는 캐시된 결과를 반환
print(example_instance.average_age) # 출력: 30.0
# __dict__ 값 조회
print(vars(example_instance))
# __dict__ 값 삭제하여 캐싱 초기화
example_instance.pop('peoples')
# 다시 연산 수행
example_instance.averate_age
위 예제에서는 Example
클래스의 average_age
속성을 @cached_property
로 데코레이트 하였다.
해당 속성은 주어진 사람들의 나이 평균을 계산하는데, 이 때 처음 접근할 때에는 계산 로직을 수행하고, 이후에는 캐시된 결과를 반환한다.
이런 기능이 가능한 이유는 첫 호출 이후 객체의 __dict__
에 결과 값이 저장되기 때문이다.
print(vars(example_instance))
# output
{'peoples': [{'name': 'Alice', 'age': 30}, {'name': 'Bob', 'age': 25}, {'name': 'Charlie', 'age': 35}], 'average_age': 30.0}
따라서 다음과 같이 __dict__
의 값을 지우게 되면 캐싱된 값이 무효화되고 다시 연산을 수행하게 된다.
# __dict__ 값 삭제하여 캐싱 초기화
example_instance.pop('peoples')
# 다시 연산 수행
example_instance.averate_age
• property의 호출 방법?
위에서 작성한 샘플 코드를 다시 살펴봐보자.
# ...
# 인스턴스 생성
example_instance = Example(people_data)
# 처음 average_age에 접근하면 계산이 수행됨
print(example_instance.average_age) # 출력: 나이 평균 계산 중... 30.0
# 두 번째부터는 캐시된 결과를 반환
print(example_instance.average_age) # 출력: 30.0
# ...
여기서 example_instance
인스턴스에서 average_age
를 호출할 때 ()
를 붙이지 않고 호출을 한다.
보통 메소드를 호출할 때에는 다음과 같이 호출해야 하는데
average_age()
예제에서는 왜 average_age
를 속성처럼 호출해서 사용하는 걸까?
그 이유는 프로퍼티(property)가 메소드에 데코레이트 된 경우 일반적인 메서드처럼 호출하지 않고 속성처럼 접근할 수 있기 때문이다.
@cached_property
를 데코레이터를 사용하면 메서드를 속성으로 변환하는데, 이렇게 하면 메서드를 호출하는 것이 아니라 속성처럼 접근할 수 있게된다. 따라서 괄호를 사용하지 않는다.
이와 대조적으로, 만약에 @property
를 사용하여 메서드를 속성으로 변환하지 않았다면, 해당 메서드를 호출할 때에는 괄호를 사용해야 한다.