Python缓存封装案例如何封装缓存工具

wen python案例 29

本文目录导读:

Python缓存封装案例如何封装缓存工具

  1. 基础缓存封装
  2. 高级缓存封装
  3. 实际应用示例
  4. 使用示例

我来帮你实现一个完整的Python缓存工具封装,包含多种缓存策略和最佳实践。

基础缓存封装

1 简单内存缓存

import time
import threading
from functools import wraps
from typing import Any, Optional, Dict, Callable
class SimpleCache:
    """简单内存缓存"""
    def __init__(self, default_ttl: int = 300):
        self._cache: Dict[str, tuple] = {}
        self._default_ttl = default_ttl
        self._lock = threading.RLock()
    def get(self, key: str) -> Optional[Any]:
        """获取缓存值"""
        with self._lock:
            if key not in self._cache:
                return None
            value, expiry = self._cache[key]
            if expiry and time.time() > expiry:
                del self._cache[key]
                return None
            return value
    def set(self, key: str, value: Any, ttl: Optional[int] = None):
        """设置缓存"""
        with self._lock:
            expiry = time.time() + (ttl or self._default_ttl)
            self._cache[key] = (value, expiry)
    def delete(self, key: str):
        """删除缓存"""
        with self._lock:
            self._cache.pop(key, None)
    def clear(self):
        """清空缓存"""
        with self._lock:
            self._cache.clear()
    def __contains__(self, key: str) -> bool:
        return self.get(key) is not None

2 装饰器实现

class cached:
    """缓存装饰器"""
    def __init__(self, ttl: int = 300, cache: Optional[SimpleCache] = None):
        self.ttl = ttl
        self.cache = cache or SimpleCache()
    def __call__(self, func: Callable) -> Callable:
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 创建缓存键
            key = self._make_key(func.__name__, args, kwargs)
            # 尝试获取缓存
            result = self.cache.get(key)
            if result is not None:
                return result
            # 执行函数
            result = func(*args, **kwargs)
            self.cache.set(key, result, self.ttl)
            return result
        return wrapper
    @staticmethod
    def _make_key(func_name: str, args: tuple, kwargs: dict) -> str:
        """生成缓存键"""
        key_parts = [func_name]
        key_parts.extend(str(arg) for arg in args)
        key_parts.extend(f"{k}:{v}" for k, v in sorted(kwargs.items()))
        return ":".join(key_parts)

高级缓存封装

1 分层缓存实现

import json
import pickle
from typing import List, Optional, Callable
class RedisCache:
    """Redis缓存适配器"""
    def __init__(self, redis_client, prefix: str = "cache:"):
        self.client = redis_client
        self.prefix = prefix
    def get(self, key: str) -> Optional[Any]:
        value = self.client.get(f"{self.prefix}{key}")
        if value:
            return pickle.loads(value)
        return None
    def set(self, key: str, value: Any, ttl: int = 300):
        self.client.setex(
            f"{self.prefix}{key}",
            ttl,
            pickle.dumps(value)
        )
    def delete(self, key: str):
        self.client.delete(f"{self.prefix}{key}")
class MultiLevelCache:
    """多级缓存"""
    def __init__(self, caches: List[object]):
        self.caches = caches
    def get(self, key: str) -> Optional[Any]:
        for i, cache in enumerate(self.caches):
            value = cache.get(key)
            if value is not None:
                # 回写上一级缓存
                for j in range(i - 1, -1, -1):
                    self.caches[j].set(key, value)
                return value
        return None
    def set(self, key: str, value: Any, ttl: int = 300):
        for cache in self.caches:
            cache.set(key, value, ttl)
    def delete(self, key: str):
        for cache in self.caches:
            cache.delete(key)
# 使用示例
# memory_cache = SimpleCache(ttl=60)
# redis_cache = RedisCache(redis_client)
# cache = MultiLevelCache([memory_cache, redis_cache])

2 缓存管理器封装

from enum import Enum
from typing import Dict, Any, Optional
import hashlib
import logging
logger = logging.getLogger(__name__)
class CacheStrategy(Enum):
    """缓存策略"""
    LRU = "lru"
    LFU = "lfu"
    FIFO = "fifo"
    TTL = "ttl"
class CacheManager:
    """缓存管理器"""
    def __init__(self, 
                 default_ttl: int = 300,
                 max_size: int = 1000,
                 strategy: CacheStrategy = CacheStrategy.TTL):
        self.default_ttl = default_ttl
        self.max_size = max_size
        self.strategy = strategy
        self._cache: Dict[str, Any] = {}
        self._expiry: Dict[str, float] = {}
        self._access_count: Dict[str, int] = {}
        self._access_order: list = []
    def get(self, key: str) -> Optional[Any]:
        """获取缓存"""
        if key not in self._cache:
            return None
        # 检查过期
        if self._is_expired(key):
            self.delete(key)
            return None
        # 更新访问信息
        self._update_access(key)
        logger.debug(f"Cache hit: {key}")
        return self._cache[key]
    def set(self, key: str, value: Any, ttl: Optional[int] = None):
        """设置缓存"""
        # 检查容量
        if len(self._cache) >= self.max_size and key not in self._cache:
            self._evict_one()
        # 设置缓存
        self._cache[key] = value
        self._expiry[key] = time.time() + (ttl or self.default_ttl)
        self._update_access(key)
        logger.debug(f"Cache set: {key}")
    def delete(self, key: str):
        """删除缓存"""
        self._cache.pop(key, None)
        self._expiry.pop(key, None)
        self._access_count.pop(key, None)
        if key in self._access_order:
            self._access_order.remove(key)
    def clear(self):
        """清空缓存"""
        self._cache.clear()
        self._expiry.clear()
        self._access_count.clear()
        self._access_order.clear()
    def _is_expired(self, key: str) -> bool:
        """检查是否过期"""
        expiry = self._expiry.get(key)
        return expiry and time.time() > expiry
    def _update_access(self, key: str):
        """更新访问信息"""
        # 更新访问次数
        self._access_count[key] = self._access_count.get(key, 0) + 1
        # 更新访问顺序
        if key in self._access_order:
            self._access_order.remove(key)
        self._access_order.append(key)
    def _evict_one(self):
        """淘汰一个缓存项"""
        if not self._cache:
            return
        if self.strategy == CacheStrategy.LRU:
            # 淘汰最久未使用的
            key = self._access_order[0]
        elif self.strategy == CacheStrategy.LFU:
            # 淘汰使用频率最低的
            key = min(self._access_count, key=self._access_count.get)
        else:
            # 默认淘汰第一个
            key = next(iter(self._cache))
        self.delete(key)
        logger.debug(f"Cache evicted: {key}")
    def get_stats(self) -> dict:
        """获取缓存统计信息"""
        return {
            'size': len(self._cache),
            'max_size': self.max_size,
            'strategy': self.strategy.value,
            'access_count': sum(self._access_count.values())
        }
# 工厂函数
def create_cache(backend: str = 'memory', **kwargs) -> Any:
    """创建缓存实例"""
    backends = {
        'memory': SimpleCache,
        'manager': CacheManager,
        'redis': RedisCache
    }
    cache_class = backends.get(backend)
    if not cache_class:
        raise ValueError(f"Unknown cache backend: {backend}")
    return cache_class(**kwargs)

实际应用示例

1 数据库查询缓存

class DatabaseCache:
    """数据库查询缓存"""
    def __init__(self, cache_instance):
        self.cache = cache_instance
    def query_with_cache(self, query: str, ttl: int = 60):
        """带缓存的数据库查询"""
        cache_key = self._generate_key(query)
        # 尝试获取缓存
        result = self.cache.get(cache_key)
        if result is not None:
            return result
        # 执行查询
        result = self._execute_query(query)
        # 缓存结果
        self.cache.set(cache_key, result, ttl)
        return result
    @staticmethod
    def _generate_key(query: str) -> str:
        """生成缓存键"""
        return f"db:{hashlib.md5(query.encode()).hexdigest()}"
    def _execute_query(self, query: str):
        """执行数据库查询"""
        # 实际数据库查询逻辑
        pass

2 API响应缓存

class APICache:
    """API响应缓存"""
    def __init__(self, cache_instance):
        self.cache = cache_instance
    def cached_api_request(self, 
                          url: str, 
                          method: str = 'GET',
                          headers: dict = None,
                          params: dict = None,
                          ttl: int = 300):
        """带缓存的API请求"""
        cache_key = self._make_cache_key(url, method, params)
        # 检查缓存
        if method.upper() == 'GET':
            cached_response = self.cache.get(cache_key)
            if cached_response:
                return cached_response
        # 执行请求
        import requests
        response = requests.request(
            method, url, 
            headers=headers, 
            params=params
        )
        # 缓存GET请求结果
        if method.upper() == 'GET' and response.status_code == 200:
            self.cache.set(cache_key, response.json(), ttl)
        return response.json()
    @staticmethod
    def _make_cache_key(url: str, method: str, params: dict = None) -> str:
        """生成缓存键"""
        import json
        key_parts = [url, method]
        if params:
            key_parts.append(json.dumps(params, sort_keys=True))
        return "|".join(key_parts)

使用示例

# 创建缓存实例
cache = CacheManager(default_ttl=300, max_size=1000)
# 使用装饰器
@cached(ttl=60, cache=cache)
def expensive_function(user_id: int):
    """模拟耗时操作"""
    import time
    time.sleep(2)  # 模拟耗时
    return {"user_id": user_id, "data": "expensive_result"}
# 直接使用
cache.set("my_key", {"value": "test_data"}, ttl=120)
result = cache.get("my_key")
# 使用缓存管理器
cache_manager = CacheManager(strategy=CacheStrategy.LRU)
cache_manager.set("key1", "value1", ttl=60)
cache_manager.delete("key1")
# 获取统计信息
stats = cache_manager.get_stats()
print(f"Cache stats: {stats}")

这个缓存工具封装提供了:

  1. 多种缓存策略:TTL、LRU、LFU等
  2. 线程安全:使用锁机制保证并发安全
  3. 装饰器支持:方便快速缓存函数结果
  4. 统计功能:监控缓存使用情况
  5. 可扩展性:支持Redis等外部存储
  6. 错误处理:完善的日志记录和异常处理

可以根据实际需求选择合适的缓存实现和策略。

抱歉,评论功能暂时关闭!