如何在Python argparse中重复调用子命令收集多组配置
解决argparse重复调用subcommand的问题
你遇到的问题是因为argparse的子命令解析器默认只支持单次子命令调用——当你在第一个config之后再传入第二个config时,解析器会把它当作第一个config子命令的未知参数,所以抛出unrecognized arguments错误。
下面提供两种解决方案,分别适配你的输入习惯和更简洁的argparse原生用法:
方案1:手动循环解析重复的config子命令(匹配你的输入格式)
我们可以跳过argparse的subparsers自动处理,手动遍历命令行参数,每次解析一组config相关的参数,直到所有参数处理完成:
import argparse def parse_single_config(args): # 定义单个config子命令的参数解析器(不包含help,避免顶层解析器冲突) config_parser = argparse.ArgumentParser(prog='PROG config', add_help=False) config_parser.add_argument('--user', required=True) config_parser.add_argument('--password', required=True) config_parser.add_argument('--configname', required=True) return config_parser.parse_args(args) def main(): # 顶层解析器只用来捕获未处理的参数 top_parser = argparse.ArgumentParser(prog='PROG') remaining_args = top_parser.parse_known_args()[1] configs = [] while remaining_args: # 检查当前参数是否是config子命令 if remaining_args[0] != 'config': top_parser.error(f"Unrecognized argument: {remaining_args[0]}") # 找到下一个config的位置,分割当前组的参数 next_config_pos = None for idx, arg in enumerate(remaining_args[1:], 1): if arg == 'config': next_config_pos = idx break # 提取当前组的参数,并更新剩余参数列表 if next_config_pos is not None: current_group_args = remaining_args[1:next_config_pos] remaining_args = remaining_args[next_config_pos:] else: current_group_args = remaining_args[1:] remaining_args = [] # 解析当前组的config参数 config = parse_single_config(current_group_args) configs.append(config) # 保存每个配置到对应的文件 for cfg in configs: with open(cfg.configname, 'w') as f: f.write(f"[user] {cfg.user}\n") f.write(f"[password] {cfg.password}\n") print(f"Successfully saved {len(configs)} configuration files.") if __name__ == '__main__': main()
测试你的命令:
$ python myfile.py config --user 'abc1' --password 'def1' --configname 'first' config --user 'abc2' --password 'def2' --configname 'second'
运行后会生成first和second两个文件,内容完全符合你的需求。
方案2:调整参数格式,用argparse原生多值参数(代码更简洁)
如果可以接受调整输入格式,我们可以让config子命令的参数接受多个值,利用argparse的nargs='+'特性:
import argparse def main(): parser = argparse.ArgumentParser(prog='PROG') subparsers = parser.add_subparsers(dest='command', required=True) # 定义config子命令,参数都接受多个值 config_parser = subparsers.add_parser('config', help='Save multiple configurations') config_parser.add_argument('--user', required=True, nargs='+', help='List of user names') config_parser.add_argument('--password', required=True, nargs='+', help='List of passwords matching users') config_parser.add_argument('--configname', required=True, nargs='+', help='List of config file names') args = parser.parse_args() # 校验三个参数的数量是否一致 if len(args.user) != len(args.password) or len(args.user) != len(args.configname): parser.error("The number of users, passwords, and config names must be the same") # 保存每个配置 for user, pwd, fname in zip(args.user, args.password, args.configname): with open(fname, 'w') as f: f.write(f"[user] {user}\n") f.write(f"[password] {pwd}\n") print(f"Successfully saved {len(args.user)} configuration files.") if __name__ == '__main__': main()
这种方式的输入命令改为:
$ python myfile.py config --user abc1 abc2 --password def1 def2 --configname first second
优点是代码更简洁,利用argparse原生功能,不需要手动处理参数分割;缺点是输入格式和你原本的需求略有不同。
总结
- 如果你必须保留原有的多次
config子命令输入格式,选择方案1; - 如果你可以调整输入格式,方案2的代码更简洁易维护。
内容的提问来源于stack exchange,提问作者Ankur Agarwal
相关产品推荐
相关产品推荐

