如何让常量模块中的get_constants方法仅执行一次以提升性能?
嗨,针对你想让get_constants()方法每个参数只执行一次的需求,我整理了几个实用的方案,你可以根据自己的场景选择:
Python的functools.lru_cache装饰器专门用来缓存函数的返回结果,只要你的get_constants参数是可哈希类型(比如字符串、数字),用它就非常方便,代码改动也最小。
实现步骤很简单:
- 导入
functools模块 - 给
get_constants加上缓存装饰器
示例代码:
import functools @functools.lru_cache(maxsize=None) # maxsize=None表示无限制缓存所有参数组合 def get_constants(key): # 这里是原来的常量生成逻辑,比如从文件/数据库读取,或者动态生成 print(f"执行get_constants({key})") # 用来验证是否重复执行 if key == "1": return {"value1": "value1", "value2": "value2"} elif key == "2": return {"value3": "value3", "value4": "value4"} class Labels(): Table = get_constants("1") Table_2 = get_constants("2") # 测试:多次访问也不会重复执行get_constants print(Labels.Table) print(Labels.Table) print(Labels.Table_2)
你会发现控制台只会打印一次执行get_constants(1)和执行get_constants(2),后续访问都是直接取缓存的结果。
如果你的常量key是固定的(比如只有"1"和"2"),可以在模块加载的时候就提前计算好所有需要的常量,然后在类里直接引用这些预计算的结果。这种方式最直接,完全避免了重复调用的可能,可读性也很高。
示例代码:
def get_constants(key): print(f"执行get_constants({key})") if key == "1": return {"value1": "value1", "value2": "value2"} elif key == "2": return {"value3": "value3", "value4": "value4"} # 模块初始化时预计算所有需要的常量 _PRECOMPUTED_CONST_1 = get_constants("1") _PRECOMPUTED_CONST_2 = get_constants("2") class Labels(): Table = _PRECOMPUTED_CONST_1 Table_2 = _PRECOMPUTED_CONST_2
如果你不想依赖functools,可以自己在get_constants内部维护一个缓存字典,手动控制缓存逻辑,灵活性更高——比如后续需要给缓存加过期、清理逻辑的话,自己改起来更方便。
示例代码:
def get_constants(key): # 初始化缓存字典,只在第一次调用时执行 if not hasattr(get_constants, "_cache"): get_constants._cache = {} # 如果key不在缓存里,才执行生成逻辑 if key not in get_constants._cache: print(f"执行get_constants({key})") if key == "1": get_constants._cache[key] = {"value1": "value1", "value2": "value2"} elif key == "2": get_constants._cache[key] = {"value3": "value3", "value4": "value4"} return get_constants._cache[key] class Labels(): Table = get_constants("1") Table_2 = get_constants("2")
其实你原来的代码里,Labels.Table = get_constants("1")这行是在类定义阶段执行的——也就是说Python加载这个类的时候就会调用一次get_constants("1"),之后不管创建多少个Labels实例,或者多少次访问Labels.Table,都不会再调用get_constants了。如果你只是担心类属性赋值时重复调用,那其实本来就不会重复执行~但如果get_constants还会被其他地方调用,那上面的缓存方案就非常有用了。
内容的提问来源于stack exchange,提问作者user3810

