如何将方法名作为参数调用其他方法?类设计及装饰器应用咨询
优化方案与设计建议
一、现有代码的问题
- 硬编码字符串判断指标,新增指标时必须修改
evaluate方法,违反开闭原则 - 参数列表固定
a,b,c,无法适配参数数量不同的新指标 - 语法错误:
returns应为return,判断条件里的=要改成==,且return score[0]会报错(metric1和metric2返回的是数值,不是可索引的序列)
二、更优实现方案
1. 方法映射+动态参数适配
把指标名称与对应方法存入字典,用*args和**kwargs适配不同指标的参数,新增指标只需添加方法并更新映射:
class A: def __init__(self, region): self.region = region # 建立指标名称到方法的映射 self.metric_map = { 'metric1': self.metric1, 'metric2': self.metric2 } def metric1(self, a, b): return a * b def metric2(self, a, b, c): return self.metric1(a, b) + c def evaluate(self, metric, *args, **kwargs): if metric not in self.metric_map: raise ValueError(f"不支持的指标:{metric}") return self.metric_map[metric](*args, **kwargs) # 使用示例 obj1 = A('XYZ') print(obj1.evaluate('metric1', 2, 3)) # 输出6 print(obj1.evaluate('metric2', 2, 3, 4)) # 输出10
2. 装饰器自动注册指标
用装饰器自动将指标方法加入映射,新增指标时只需给方法加装饰器,无需手动修改metric_map:
class A: def __init__(self, region): self.region = region self.metric_map = {} def register_metric(self, metric_name): def decorator(func): self.metric_map[metric_name] = func return func return decorator @register_metric('metric1') def metric1(self, a, b): return a * b @register_metric('metric2') def metric2(self, a, b, c): return self.metric1(a, b) + c def evaluate(self, metric, *args, **kwargs): if metric not in self.metric_map: raise ValueError(f"不支持的指标:{metric}") return self.metric_map[metric](*args, **kwargs)
三、依赖evaluate输出的后续方法设计合理性
这种设计完全合理,类的核心就是封装相关行为与状态,后续方法依赖evaluate的输出是自然的逻辑。推荐两种实现方式:
- 直接调用
evaluate:适合单次计算场景class A: # 省略前面的代码... def post_calculate(self, metric, *args, **kwargs): base_score = self.evaluate(metric, *args, **kwargs) # 示例:根据地区调整分数 return base_score * 1.2 if self.region == 'XYZ' else base_score * 0.9 - 保存结果为实例属性:适合多次复用同一指标结果的场景
class A: def __init__(self, region): self.region = region self.metric_map = {} self.last_score = None # 保存最近一次计算的分数 # 省略前面的代码... def evaluate(self, metric, *args, **kwargs): if metric not in self.metric_map: raise ValueError(f"不支持的指标:{metric}") self.last_score = self.metric_map[metric](*args, **kwargs) return self.last_score def post_calculate(self): if self.last_score is None: raise ValueError("请先调用evaluate方法获取分数") return self.last_score * 0.8 # 后续计算逻辑
四、装饰器的其他优化场景
除了自动注册指标,还可以用装饰器给所有指标添加通用逻辑,比如参数校验、日志记录:
class A: def __init__(self, region): self.region = region self.metric_map = {} def register_metric(self, metric_name): def decorator(func): def wrapper(*args, **kwargs): # 通用参数校验:确保所有参数为数值类型 for arg in args: if not isinstance(arg, (int, float)): raise TypeError(f"参数{arg}必须是数值类型") return func(*args, **kwargs) self.metric_map[metric_name] = wrapper return wrapper return decorator @register_metric('metric1') def metric1(self, a, b): return a * b
内容的提问来源于stack exchange,提问作者JamesHunt
相关产品推荐
相关产品推荐

