python 3.9 버전부터 functools
모듈에서 제공하는 @cache
데코레이터는 개발 시 자주 사용되는 데코레이터 중 하나이며, 나 역시 자주 사용하고 있다. 쓰다 보니 정확하게 이해하지 못하고 쓰는 경우도 있는 것 같아 정리하려고 한다.
1. @cache 데코레이터
@cache
데코레이터는 기본적으로 함수의 인자를 가지고 메모이제이션(Memoization) 기법을 사용하여 캐싱하는 방식이다. 즉, 함수의 인자가 이전에 입력으로 들어온 적이 없으면 계산하고, 한 번 계산된 후에는 그 결과를 저장해 두어 동일한 입력이 들어왔을 때 캐시된 결과를 반환한다. 데코레이터이기 때문에 함수 위에 붙여서 간단하게 적용할 수 있다.
1.1. 구현 시 주의할 점
- Hashable:
@cache
데코레이터는 함수의 인자를 해시 하여 결과를 저장한다. 따라서 함수의 인자는 모두 hashable 해야 한다. 다시 말해list
,dict
와 같은 가변형 객체가 함수의 인자로 사용될 경우,@cache
를 사용할 수 없다. 이런 경우 꼭 cache를 사용해야 한다면 가변형 함수 인자를 불변형 객체인tuple
로 바꾸어 받는 방법이 있다. 혹은, 인자로 특정 클래스의 인스턴스를 받게 되고 인스턴스가 가변형 객체일 경우, 클래스 내부에__hash__
함수를 별도 정의하여 불변형 객체만 사용하여 해시하도록 강제하는 방법이 있다.
@cache
def test_func(lst):
return sum(lst)
test_func([1, 2, 3]) # TypeError: unhashable type: 'list'
- 메모리: 캐시의 크기를 제한하지 않기 때문에 매우 많은 호출이 이루어지는 경우 메모리 사용량에 주의해야 한다. 이것이 문제가 될 수 있는 경우에 `@lru_cache` 데코레이터를 사용하여 캐시의 크기를 제한하는 형태로 조절할 수 있다고 한다.
1.2. 코드 예시
from functools import cache
@cache
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
# 첫 번째 호출
print(fibonacci(10)) # 계산 수행
# 두 번째 호출
print(fibonacci(10)) # 캐시에 저장된 결과가 반환
동일한 입력이 들어올 확률이 높아 메모이제이션이 필요한 경우 간단한 형태로 적용이 가능하기 때문에 매우 유용하다. 재귀 함수나 (실제로는 피하는 구현방식) REST API 응답 처리 함수 같은 경우에 매우 유용하게 쓰일 수 있다.
2. Singleton
동일한 결과 혹은 객체를 재사용하는 개념에서 일부 유사하긴 하여 별도 정리하려고 한다. 사실 메모리 효율성 높이는 측면에서만 유사하지 전혀 다른 개념이다. 싱글톤(Singleton) 패턴은 하나의 클래스에 대해 단 하나의 인스턴스만 생성되도록 보장하는 디자인 패턴이다. 이는 하나의 객체를 공유해야 하는 경우에 사용되는데, 대표적으로 데이터베이스를 들 수 있다.
python에서 싱글톤 패턴을 구현하는 방법은 여러 가지가 있지만, @cache
데코레이터와 마찬가지로 인스턴스를 캐싱 하여 새로 인스턴스가 생성될 때 기존 인스턴스를 반환하는 형태가 일반적이다.
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
3. 차이점
싱글톤 패턴과 @cache
는 모두 메모리를 절약하고 중복 연산, 생성을 피하는 목적은 같지만 작동하는 방식과 시나리오는 다르다.
- @cache: 함수 호출 결과를 캐시 하여 동일한 입력에 대해 불필요한 계산을 피한다. 함수의 호출 결과에 적용된다. pure function에서 많이 사용된다.
- 싱글톤: 객체의 생성 횟수를 제한하여 전역에서 하나의 인스턴스만 사용하도록 보장한다. 클래스에 적용되어, 클래스의 인스턴스가 하나만 존재하도록 한다. 함수 결과의 재사용이 아닌 객체의 재사용이다.
두 개념은 관련은 있을 수 있지만 서로 다른 목적을 가진 개념이며 상황에 따라 보완적으로 사용할 수는 있다. (싱글톤 클래스의 메소드에 @cache
데코레이터를 사용하는 등)
'개발' 카테고리의 다른 글
[Python] FastAPI 성능 최적화 (1) | 2024.10.05 |
---|