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

如何为带固定参数的类方法仅做一次包装?避免缓存重复初始化

解决方法

针对你需要避免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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 03:50:03