如何为带固定参数的类方法仅做一次包装?避免缓存重复初始化
解决方法
针对你需要避免cache重复初始化、仅对item.foo执行一次包装的需求,除了在循环前初始化缓存外,还有以下几种实用实现方式:
方法一:给Foo实例方法添加包装标记
通过给Foo实例的foo方法添加自定义属性,标记是否已针对当前param1完成包装,避免重复执行wrapper中的缓存初始化逻辑:
class Foo: _count = 0 def foo(self, param2): self._count += param2 class Bar: _collection = [Foo(), Foo(), Foo()] def bar(self, param1, param2): for item in self._collection: # 检查是否已为当前param1包装过foo方法 if not hasattr(item.foo, '_wrapped_param') or item.foo._wrapped_param != param1: original_foo = item.foo wrapped_foo = wrapper(original_foo, param1) # 标记已包装的param值 wrapped_foo._wrapped_param = param1 # 替换实例的foo方法为包装后的版本 item.foo = wrapped_foo item.foo(param2) def wrapper(func, param1): # 仅在第一次包装时执行缓存初始化 cache = {param1: 'param_value'} print(f"初始化cache: param1={param1}") def _wrapper(*args, **kwargs): print(cache[param1]) return func(*args, **kwargs) return _wrapper bar = Bar() bar.bar(1, 2) bar.bar(1, 3) # 第二次调用不会重复初始化cache
方法二:给wrapper添加记忆缓存
利用functools.lru_cache缓存wrapper的返回结果,相同的func(即同一个Foo实例的foo方法)和param1会复用已生成的包装函数,从而避免重复初始化cache:
from functools import lru_cache class Foo: _count = 0 def foo(self, param2): self._count += param2 class Bar: _collection = [Foo(), Foo(), Foo()] def bar(self, param1, param2): for item in self._collection: wrapped_function = wrapper(item.foo, param1) wrapped_function(param2) # 缓存wrapper的返回值,key为func和param1的组合 @lru_cache(maxsize=None) def wrapper(func, param1): cache = {param1: 'param_value'} print(f"初始化cache: param1={param1}") def _wrapper(*args, **kwargs): print(cache[param1]) return func(*args, **kwargs) return _wrapper bar = Bar() bar.bar(1, 2) bar.bar(1, 3) # 同一个func+param1组合不会重复初始化cache
方法三:用类封装包装逻辑
创建专门的包装器类,将cache和包装逻辑封装在一起,通过替换Foo实例的foo方法为包装器实例,确保缓存仅初始化一次:
class Foo: _count = 0 def foo(self, param2): self._count += param2 class FooMethodWrapper: def __init__(self, original_func, param1): self.original_func = original_func # 初始化缓存,仅执行一次 self.cache = {param1: 'param_value'} print(f"初始化cache: param1={param1}") def __call__(self, *args, **kwargs): print(self.cache[next(iter(self.cache.keys()))]) return self.original_func(*args, **kwargs) class Bar: _collection = [Foo(), Foo(), Foo()] def bar(self, param1, param2): for item in self._collection: # 检查foo是否已被包装 if not isinstance(item.foo, FooMethodWrapper): item.foo = FooMethodWrapper(item.foo, param1) item.foo(param2) bar = Bar() bar.bar(1, 2) bar.bar(1, 3)
内容的提问来源于stack exchange,提问作者Aleksandr Lekontsev
相关产品推荐
相关产品推荐

