You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中实现可自主控制的缓存的最优方案咨询

如何实现可被函数多次访问和修改的自定义缓存?

我希望创建一个可供函数多次访问和修改的缓存结构,目前已经尝试了以下三种实现方式:

1. 使用全局变量

def func():
    global cache
    cached_data = cache.get("some_key")
    if not cached_data:
        # 生成或获取数据的逻辑
        ...
    # 后续逻辑
    ...

2. 将缓存作为参数传入函数

def func(cache):
    cache.update({"stuff": 42})
    my_stuff = cache.get("stuff")

def main():
    func_cache = {}
    func(func_cache)

if __name__ == "__main__":
    main()

3. 将缓存封装在类中

class MyFunc:
    cache = {}
    @staticmethod
    def func():
        cached_data = MyFunc.cache.get("stuff")
    
def main():
    MyFunc.func()

if __name__ == "__main__":
    main()

我了解functools.lru_cache这类工具,但本次需求中我希望能完全自主控制缓存的存储内容,所以想咨询是否有更优的常用实现方案,帮助自己和有相同需求的开发者。


推荐的自定义缓存实现方案

针对自主控制缓存的需求,以下几种方案在Python中较为常用且各有优势:

1. 使用闭包封装缓存

闭包可以在不使用全局变量或类的前提下,让函数持久化访问一个私有缓存,同时避免污染全局命名空间:

def create_cached_func():
    cache = {}
    def func():
        cached_data = cache.get("some_key")
        if not cached_data:
            # 自定义逻辑生成数据
            cache["some_key"] = "new_data"
        print(cache)
    return func

# 使用方式
cached_func = create_cached_func()
cached_func()  # 输出: {'some_key': 'new_data'}
cached_func()  # 输出: {'some_key': 'new_data'}
  • 优点:缓存是函数私有状态,不会被其他代码意外修改;无需类结构,代码简洁。
  • 缺点:如果需要多个函数共享同一缓存,需要额外处理闭包的共享逻辑。

2. 自定义装饰器封装缓存

把缓存逻辑封装成装饰器,既可以复用缓存逻辑,又能保持业务函数的简洁:

def custom_cache_decorator(cache):
    def decorator(func):
        def wrapper(*args, **kwargs):
            # 自定义缓存键生成逻辑(比如基于参数)
            cache_key = f"{args}_{kwargs}"
            if cache_key not in cache:
                cache[cache_key] = func(*args, **kwargs)
            return cache[cache_key]
        return wrapper
    return decorator

# 使用方式
my_cache = {}
@custom_cache_decorator(my_cache)
def compute_expensive_data(a, b):
    print("计算数据中...")
    return a + b

compute_expensive_data(1, 2)  # 输出: 计算数据中... 3
compute_expensive_data(1, 2)  # 直接返回3,不会重新计算
# 可以自主修改缓存
my_cache["(1, 2)_{}"] = 100
compute_expensive_data(1, 2)  # 返回100
  • 优点:缓存逻辑与业务逻辑分离,可复用;完全自主控制缓存的读取、修改和清除。
  • 缺点:需要手动处理缓存键的生成逻辑,避免键冲突。

3. 使用contextvars实现上下文隔离的缓存(适用于异步/多线程场景)

如果你的代码运行在异步或多线程环境中,contextvars可以保证每个上下文拥有独立的缓存,避免并发冲突:

import contextvars

cache_var = contextvars.ContextVar("custom_cache", default={})

def func():
    cache = cache_var.get()
    cached_data = cache.get("some_key")
    if not cached_data:
        cache["some_key"] = "context_data"
        cache_var.set(cache)
    print(cache)

# 在主线程使用
func()  # 输出: {'some_key': 'context_data'}
# 在新线程/任务中,缓存是独立的
import threading
threading.Thread(target=func).start()  # 输出: {'some_key': 'context_data'},但与主线程缓存是不同的实例
  • 优点:天然支持并发场景,无需手动加锁;缓存与上下文绑定,避免交叉污染。
  • 缺点:仅适用于需要上下文隔离的场景,普通单线程场景略显复杂。

4. 使用类实例属性存储缓存(改进原有类方案)

原有类方案使用了类变量(所有实例共享),如果需要每个实例独立缓存,可以改用实例属性:

class CachedFunc:
    def __init__(self):
        self.cache = {}
    
    def func(self):
        cached_data = self.cache.get("stuff")
        if not cached_data:
            self.cache["stuff"] = 42
        print(self.cache)

# 使用方式
instance1 = CachedFunc()
instance1.func()  # 输出: {'stuff': 42}
instance2 = CachedFunc()
instance2.func()  # 输出: {'stuff': 42},两个实例缓存独立
  • 优点:可以灵活控制缓存是实例独立还是类共享;类结构便于扩展更多缓存管理方法(比如清除缓存、过期逻辑)。
  • 缺点:需要创建类实例才能使用,相比闭包多了一层结构。

内容的提问来源于stack exchange,提问作者ugo_capeto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 12:15:35