如何利用装饰器复用基于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
相关产品推荐
相关产品推荐

