【问题标题】:How can I define global options with sub-parsers in python argparse?如何在 python argparse 中使用子解析器定义全局选项?
【发布时间】:2016-10-22 08:32:36
【问题描述】:

我正在尝试弄清楚如何使用 pythons arparse 库在子解析器场景中添加全局选项。

现在我的代码如下所示:

def parseArgs(self):
    parent_parser = argparse.ArgumentParser(add_help=False)
    parent_parser.add_argument('--debug', default=False, required=False,
        action='store_true', dest="debug", help='debug flag')

    main_parser = argparse.ArgumentParser()
    main_parser.add_argument('--debug', default=False, required=False,
        action='store_true', dest="debug", help='debug flag')

    service_subparsers = main_parser.add_subparsers(title="category",
        dest="category")
    agent_parser = service_subparsers.add_parser("agent",
        help="agent commands", parents=[parent_parser])
    return main_parser.parse_args()

这适用于命令行./test --help 并且--debug 选项被列为全局:

用法:测试 [-h] [--debug] {agent} ... 可选参数: -h, --help 显示此帮助信息并退出 --debug 调试标志 类别: {代理人} 代理 代理命令

但是,当我使用命令行./test agent --help 触发代理子解析器时,--debug 选项现在不再列为全局选项,而是列为子解析器的选项。此外,它现在必须指定为 ./test agent --debug./test --debug agent 不再有效:

用法:测试代理 [-h] [--debug] 可选参数: -h, --help 显示此帮助信息并退出 --debug 调试标志

我想做的是将--debug 定义为全局的,以便始终可以为所有子解析器指定它,并在帮助输出中适当地列出。

【问题讨论】:

    标签: python argparse


    【解决方案1】:

    main_parser将默认值填入namespaceFalsedebug);如果遇到--debug,它会将debug 更改为True。当它看到agent 字符串时,它会调用子解析器,将剩余的参数字符串和它一直使用的命名空间传递给它。

    现在子解析器执行普通解析器的工作 - 如果为其参数填充默认值,则将 default 设置为 False。如果在剩余字符串中遇到--debug,它会将其更改为True。否则它会保持原样。完成后,它将命名空间传递回主解析器,然后将其返回给您的代码。

    所以

    myprog.py --debug agent --debug
    

    namespace(debug=False) 已从 False 变为 True 到 False 并返回 True。

    这是主解析器(我不喜欢在此上下文中使用“全局”)和子解析器共享相同 dest 的结果。

    有一个错误/问题试图稍微改变行为,将子解析器传递给“处女”命名空间,然后以某种方式将其结果与主解析器合并。但这产生了一些向后兼容性问题。如果需要,我可以查一下。

    目前,尝试在主解析器和子解析器中定义相同的可选项必然会给您和您的用户造成混淆。

    如果我将父级更改为

    parent_parser.add_argument('--Debug', action='store_true', help='debug flag')
    

    (不需要默认,如果与选项标志相同则为dest)

    生成的命名空间将如下所示

    1721:~/mypy$ python stack37933480.py --debug agent --Debug
    Namespace(Debug=True, category='agent', debug=True)
    

    或者我可以定义

    parent_parser.add_argument('--debug', dest='debug1', action='store_true', help='debug flag')
    

    然后得到:

    1724:~/mypy$ python stack37933480.py --debug agent --debug
    Namespace(category='agent', debug=True, debug1=True)
    

    两个地方的标志相同,但命名空间中的条目不同。解析后我可以执行以下操作:

    args.debug = args.debug or args.debug1
    

    统一这两个标志。无论需要哪种帮助,您的用户都会看到“--debug”。

    很抱歉,如果描述有点冗长,但我认为首先了解行为很重要。然后解决方案变得更加明显。

    在这种情况下,使用父级不会使问题复杂化。我假设您使用它只是为了将此调试添加到所有子解析器。

    另一种选择是只为主解析器定义debug。是的,子解析器帮助中将缺少它,但您始终可以在描述中添加注释。

    ====================

    子解析器定义采用prog 参数。如果未给出,则根据主 prog 定义。

    如果我将prog 添加为:

    agent_parser = service_subparsers.add_parser("agent",
        prog='myprog.py [--debug] agent',
        help="agent commands", parents=[parent_parser])
    

    subparser 用法变为:

    1824:~/mypy$ python3 stack37933480.py agent -h
    usage: myprog.py [--debug] agent [-h] [--debug]
    

    或者我可以将 prog 添加到 add_subparsers 定义中

    service_subparsers = main_parser.add_subparsers(title="category",
        prog='myprog.py [--debug]',
        dest="category")
    

    检查该方法的代码,看看它是如何构造默认使用前缀的。它包括main 位置,但不包括可选。

    http://bugs.python.org/issue9351 - 在这个补丁中,最初的开发者认为用户期望参数的子解析器定义应该覆盖主解析器的值和操作。另一方面,您希望主要定义具有优先权。

    http://bugs.python.org/issue24251 - 但 9351 中提出的更正给其他用户带来了问题。这就是为什么我认为最好不要在 main 和 sub 中定义相同的dest。很难满足大家的期待。

    【讨论】:

      猜你喜欢
      • 2013-12-21
      • 2018-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-03
      • 2013-10-07
      • 2013-06-09
      • 2016-05-30
      相关资源
      最近更新 更多