본문 바로가기
IT/Python

파이썬 표준 라이브러리로 '자동 만료(TTL) 딕셔너리' 만들기

by 소소메모 2025. 12. 9.
반응형

 

 

 

파이썬 표준 라이브러리로 '자동 만료(TTL) 딕셔너리' 만들기

- Redis 쓰기가 무거울때...

 

개발을 하다 보면 데이터에 유효 기간(TTL, Time To Live)을 설정하고 싶을 때가 있습니다. 보통 이럴 때 가장 먼저 떠오르는 건 Redis입니다. 하지만 간단한 스크립트나 가벼운 마이크로 서비스에서 Redis 서버를 띄우거나, cachetools 같은 외부 라이브러리를 추가하는 것은 배보다 배꼽이 더 큰 경우가 많습니다.

오늘은 파이썬의 표준 라이브러리인 collections를 활용해, 외부 의존성 0%의 '스스로 만료되는 딕셔너리'를 만드는 법을 소개합니다.

왜 dict 대신 UserDict인가?

파이썬 내장 dict를 직접 상속받는 것보다 collections.UserDict를 상속받는 것이 훨씬 안전하고 커스터마이징이 쉽습니다. 내부 데이터가 self.data라는 속성에 딕셔너리 형태로 저장되기 때문에, 데이터 조작이 매우 직관적입니다.

코드 구현: ExpiringDict

이 클래스는 데이터를 저장할 때 '현재 시간'을 함께 저장하고, 데이터를 조회할 때 '시간이 만료되었는지' 확인하는 Lazy Expiration(지연 만료) 방식을 사용합니다.

 
import time
from collections import UserDict

class ExpiringDict(UserDict):
    def __init__(self, ttl_seconds=60):
        super().__init__()
        self.ttl_seconds = ttl_seconds

    def __setitem__(self, key, value):
        # 값과 함께 데이터가 저장되는 시점(timestamp)을 튜플로 저장
        expiry_time = time.time() + self.ttl_seconds
        super().__setitem__(key, (value, expiry_time))

    def __getitem__(self, key):
        # 데이터를 가져올 때 만료 여부 체크
        value, expiry_time = super().__getitem__(key)
        
        if time.time() > expiry_time:
            # 만료되었다면 삭제 후 KeyError 발생 (혹은 None 반환 처리)
            del self[key]
            raise KeyError(f"Key '{key}' has expired.")
        
        return value

    def get(self, key, default=None):
        try:
            return self[key]
        except KeyError:
            return default

# --- 사용 예시 ---
if __name__ == "__main__":
    # 2초 뒤에 만료되는 딕셔너리 생성
    cache = ExpiringDict(ttl_seconds=2)
    
    cache['token'] = 'abc-123'
    print(f"저장 직후: {cache.get('token')}") # 출력: abc-123
    
    print("3초 대기 중...")
    time.sleep(3)
    
    print(f"3초 후 조회: {cache.get('token')}") # 출력: None

이 코드의 장점

  1. Dependency Free: pip install이 전혀 필요 없습니다. 도커 이미지를 가볍게 유지할 수 있습니다.
  2. Lazy Evaluation: 별도의 백그라운드 스레드가 돌면서 주기적으로 청소(Garbage Collection)를 하지 않습니다. 오직 데이터에 접근할 때만 검사하므로 리소스 낭비가 없습니다.
  3. 확장성: API 요청 횟수 제한(Rate Limiting)이나 임시 인증 토큰 관리에 바로 적용할 수 있습니다.

마치며

모든 문제에 거창한 아키텍처가 필요한 것은 아닙니다. 때로는 파이썬의 기본기가 가장 효율적인 해결책이 됩니다. 이 작은 클래스를 여러분의 utils.py에 넣어두면, 언젠가 Redis 설정을 하느라 낭비할 1시간을 아껴줄 것입니다.

반응형

댓글