Python固定类/方法其余参数仅修改指定参数的实现方法
实现方案
核心思路
这是典型的「固定参数绑定+可变参数遍历」场景,不需要硬编码重复书写固定参数,用闭包或者functools.partial把不变的参数提前绑定,只把需要修改的参数留作调用时传入即可,完全可以避免复制粘贴带来的代码冗余和出错概率。
基础版实现(仅修改类参数b)
首先回答你关于loop_through_B的疑问:不需要在遍历函数里额外指定方法名,方法名、其他固定类参数、固定方法参数都可以在包装层提前绑定,遍历函数只负责传递可变参数、收集结果即可。
第一步:实现通用包装函数
wrapper_fct不需要和特定类、特定方法绑定,做成通用版本即可:
from functools import partial def wrapper_fct( target_class, fixed_init_args: tuple, fixed_init_kwargs: dict, method_name: str, fixed_method_args: tuple, fixed_method_kwargs: dict, b_val ): # 合并固定参数和可变参数b实例化类,默认b是类初始化的第二个位置参数(在a之后、c之前) instance = target_class(*fixed_init_args, b_val, **fixed_init_kwargs) # 调用指定实例方法 method = getattr(instance, method_name) return method(*fixed_method_args, **fixed_method_kwargs)
第二步:为每个类提前绑定固定参数
针对用到的my_class1/my_class2/my_class3,提前把固定参数a、c,固定方法名my_method,固定方法参数d、e、f都绑定好,生成只接收b作为入参的专用函数:
# 为my_class1生成专用包装 wrap1 = partial( wrapper_fct, target_class=my_class1, fixed_init_args=(a,), fixed_init_kwargs={"c": c}, method_name="my_method", fixed_method_args=(d, e, f), fixed_method_kwargs={} ) # 测试调用:等价于 my_class1(a, 2, c).my_method(d,e,f) wrap1(2)
同理可以快速生成对应my_class2的wrap2、对应my_class3的wrap3,不需要重复书写长串参数。
第三步:实现遍历函数
遍历函数只需要接收提前绑定好的包装函数、b的取值列表即可,不需要关心具体类和方法逻辑:
def loop_through_B(wrapper, b_values=[1,2,3,4,5]): res = [] for b in b_values: res.append(wrapper(b)) return res # 直接调用即可,不需要额外传方法名 mylist1 = loop_through_B(wrap1) mylist2 = loop_through_B(wrap2) mylist3 = loop_through_B(wrap3)
对比原有循环写法,新增类的时候只需要生成一行对应包装函数,不需要在循环里重复写append逻辑;修改固定参数的时候只需要改一次绑定配置,不会出现漏改、错写参数的问题。
扩展版:支持修改方法参数、同时修改多个参数
如果需要支持修改方法参数,甚至同时修改多个类初始化参数、方法参数,只需要调整包装函数的参数拆分逻辑,用前缀区分参数属于类初始化还是方法调用即可,不需要改动整体结构:
扩展版通用包装器
def flexible_wrapper( target_class, fixed_init_args: tuple, fixed_init_kwargs: dict, method_name: str, fixed_method_args: tuple, fixed_method_kwargs: dict, **var_params ): # 拆分可变参数:init__开头的是类初始化参数,method__开头的是方法参数 init_params = {} method_params = {} for k, v in var_params.items(): if k.startswith("init__"): init_params[k.removeprefix("init__")] = v elif k.startswith("method__"): method_params[k.removeprefix("method__")] = v # 合并参数完成实例化和方法调用 instance = target_class(*fixed_init_args, **fixed_init_kwargs, **init_params) method = getattr(instance, method_name) return method(*fixed_method_args, **fixed_method_kwargs, **method_params)
扩展版多参数遍历函数
借助itertools.product可以自动生成多参数的所有组合,不需要手写多层循环:
from itertools import product def loop_multi_params(wrapper, param_grid: dict): """ param_grid格式:键为带前缀的参数名,值为该参数待遍历的取值列表 例如 {"init__b": [1,2,3], "method__e": [4,5]} 代表遍历b和e的所有组合 """ param_names = list(param_grid.keys()) value_combos = product(*[param_grid[name] for name in param_names]) res = [] for combo in value_combos: res.append(wrapper(**dict(zip(param_names, combo)))) return res
扩展版用法示例
- 仅修改方法参数e:
wrap1_flex = partial( flexible_wrapper, target_class=my_class1, fixed_init_args=(a,), fixed_init_kwargs={"b": b_default, "c": c}, method_name="my_method", fixed_method_args=(d,), fixed_method_kwargs={"f": f} ) # 调用等价于 my_class1(a, b_default, c).my_method(d, 10, f) wrap1_flex(method__e=10)
- 同时遍历类参数b和方法参数e:
res = loop_multi_params(wrap1_flex, param_grid={ "init__b": [1,2,3,4,5], "method__e": [10,20,30] })
- 同时修改多个类参数、多个方法参数时,只需要在调用时传入对应前缀的关键字参数即可,不需要修改包装器和遍历函数的代码。
内容的提问来源于stack exchange,提问作者chbot95
相关产品推荐
相关产品推荐

