Python多脚本共享命令行参数报错如何处理并减少代码重复?
问题原因
装饰器在模块导入、类定义阶段就会执行,此时存入全局注册容器_args_register的是未绑定实例的类原生方法,后续直接调用时不会自动传入self实例对象,因此触发缺失位置参数的报错。除此之外代码中还存在笔误:argparse的参数添加方法是add_argument而非add_arg。
现有代码修复方案
修改ArgumentHandler类的parse_args方法,将注册的方法绑定到当前实例后再调用,同时修正参数添加方法的笔误即可正常运行:
def parse_args(self): for func in itertools.chain(_args_register[Scripts.ALL], _args_register[self._script]): # 将类方法绑定到当前实例 bound_func = func.__get__(self, ArgumentHandler) bound_func() _args = self._parser.parse_args() return _args
修复后即可实现你需要的按脚本区分参数默认值的需求,因为参数默认值会读取实例中存储的self._script属性,和你最初的设计逻辑完全匹配。
更优的低代码重复实现方案
如果不需要保持现有的装饰器注册架构,有两种更简洁、可维护性更高的实现方式:
- 参数组封装方案
将通用参数封装为独立方法,不同脚本按需调用对应方法添加参数即可:
class BaseArgParser: def __init__(self, script, description=""): self.parser = argparse.ArgumentParser(description=description) self.script = script # 所有脚本默认加通用参数 self._add_common_args() def _add_common_args(self): self.parser.add_argument("--common-arg", default=self.script, help="全脚本通用参数") def add_train_test_args(self): """训练、测试脚本按需调用此方法添加共有参数""" self.parser.add_argument("--train-test-arg", default=self.script, help="训练测试通用参数") def parse_args(self): return self.parser.parse_args() # 训练脚本中的调用示例 def get_args(): arg_parser = BaseArgParser(Scripts.TRAIN, description=__doc__) arg_parser.add_train_test_args() # 添加脚本独有参数 arg_parser.parser.add_argument("--train-arg", default="blah", help="训练独有参数") return arg_parser.parse_args()
- 原生父解析器方案
直接使用argparse官方原生支持的parents特性实现参数复用,不需要额外引入装饰器、全局注册等逻辑:
# 定义通用父解析器,add_help设为False避免子解析器冲突 common_parser = argparse.ArgumentParser(add_help=False) common_parser.add_argument("--common-arg", help="全脚本通用参数") train_test_parser = argparse.ArgumentParser(add_help=False, parents=[common_parser]) train_test_parser.add_argument("--train-test-arg", help="训练测试通用参数") # 训练脚本中的调用示例 def get_args(): # 继承对应父解析器的所有参数 parser = argparse.ArgumentParser(description=__doc__, parents=[train_test_parser]) parser.add_argument("--train-arg", default="blah", help="训练独有参数") # 按脚本设置不同的默认值 parser.set_defaults(common_arg=Scripts.TRAIN, train_test_arg=Scripts.TRAIN) return parser.parse_args()
内容的提问来源于stack exchange,提问作者Rahul Tuli
相关产品推荐
相关产品推荐

