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

如何利用装饰器复用基于exact_match的函数行为切换逻辑?

当然可以用装饰器来搞定这个场景!这正好是装饰器擅长的活儿——把重复的逻辑抽离出来,让你的代码更简洁、易维护,以后新增同类函数时直接套装饰器就行,不用再复制粘贴那堆判断逻辑。

思路拆解

你的核心需求是:根据exact_match参数,自动切换等价性判断函数(精确匹配用_equal,非精确用is_close)。我们可以把这个“切换逻辑”封装成装饰器,让所有需要这个功能的函数直接继承这个逻辑,不用重复编写。

具体实现步骤

首先保留你原有的基础判断函数:

def is_close(a, b, rel_tol=1e-09, abs_tol=0.0): 
    return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)

def _equal(val_a, val_b): 
    """Wrapper for equality test to send in place of is_close.""" 
    return val_a == val_b

然后编写装饰器,把“根据exact_match选择判断函数”的逻辑封装进去:

def with_equivalence_switch(default_rel_tol=1e-09, default_abs_tol=0.0):
    def decorator(func):
        def wrapper(*args, exact_match=False, rel_tol=None, abs_tol=None, **kwargs):
            # 根据参数选择对应的等价性判断函数
            if exact_match:
                equivalence_func = _equal
            else:
                # 优先用调用时传入的容差,没有则用装饰器默认值
                used_rel = rel_tol if rel_tol is not None else default_rel_tol
                used_abs = abs_tol if abs_tol is not None else default_abs_tol
                # 包装is_close,让它自动使用选定的容差
                equivalence_func = lambda a, b: is_close(a, b, used_rel, used_abs)
            
            # 把处理好的判断函数传给原函数,原函数直接用就行
            return func(*args, equivalence_func=equivalence_func, **kwargs)
        return wrapper
    return decorator

接下来改造你现有的get_equivalence函数,用装饰器修饰,并且调整函数签名接收equivalence_func:

class YourFirstClass:
    @staticmethod
    @with_equivalence_switch()  # 可以在这里自定义默认容差,比如@with_equivalence_switch(default_rel_tol=1e-06)
    def get_equivalence(obj_a, obj_b, check_name=True, equivalence_func=None): 
        if check_name: 
            return obj_a.name == obj_b.name 
        # 直接用装饰器传入的equivalence_func做判断,不用再写切换逻辑
        if 'min_res' in obj_a and 'min_res' in obj_b and not equivalence_func(obj_a['min_res'], obj_b['min_res']): 
            return False 
        # 这里原代码最后return False应该是示例不全,你可以根据实际业务逻辑修改
        return True

新增函数时的复用

当你需要新增一个同样需要切换等价性判断的函数时,直接套装饰器就行,比如:

class YourSecondClass:
    @staticmethod
    @with_equivalence_switch(default_rel_tol=1e-06)
    def check_dimensions(obj_x, obj_y, equivalence_func=None):
        # 直接用equivalence_func做维度比较
        if not equivalence_func(obj_x.width, obj_y.width):
            return False
        if not equivalence_func(obj_x.height, obj_y.height):
            return False
        return True

调用方式和原来完全一致

不管是旧函数还是新函数,调用时都可以正常传exact_match参数:

# 非精确匹配(用is_close)
YourFirstClass.get_equivalence(obj1, obj2)
# 精确匹配(用_equal)
YourFirstClass.get_equivalence(obj1, obj2, exact_match=True)
# 自定义容差的非精确匹配
YourFirstClass.get_equivalence(obj1, obj2, rel_tol=1e-05)

这种方式的好处很明显:

  • 所有切换逻辑集中在装饰器里,修改一次就能同步到所有被装饰的函数
  • 新增函数时不用重复写判断代码,只需要关注业务逻辑本身
  • 可以通过装饰器参数统一配置默认容差,也支持调用时自定义容差

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 03:55:31