【问题标题】:How can I add more subparsers to an argpare parser? [duplicate]如何向 argpare 解析器添加更多子解析器? [复制]
【发布时间】:2018-04-17 05:03:32
【问题描述】:

如果我的代码调用了一个返回 ArgumentParser 的函数,该函数已经定义了一些子解析器,我该如何添加更多的子解析器?

我想这样做:

parser_with_subparsers = build_parser()
additional_subparsers = parser_with_subparsers.add_subparsers()
extra_subparser = additional_subparsers.add_parser("extra", help="extra help"))

但是当我在解释器中尝试这样做时:

>>> parser_with_subparsers = build_parser()
>>> additional_subparsers = parser_with_subparsers.add_subparsers()
usage: [-h] {original_subparser} ...
: error: cannot have multiple subparser arguments

请注意,我无权访问 build_parser() 函数的内部。

我能想到的唯一解决方案是使用parents,但这会产生以一种奇怪的方式对子解析器进行分组的副作用:

>>> child_parser = argparse.ArgumentParser(parents=[build_parser()])
>>> additional_subparsers = child_parser.add_subparsers()
>>> extra_subparser = additional_subparsers.add_parser("extra", help="extra help")
>>> extra_subparser2 = additional_subparsers.add_parser("extra2", help="extra2 help")
>>> child_parser.print_help()
usage: [-h] {original_subparser} ... {extra,extra2} ...

positional arguments:
  {original_subparser}
    original_subparser  original_subparser help
  {extra,extra2}
    extra               extra help
    extra2              extra2 help

optional arguments:
  -h, --help            show this help message and exit

我想这样做的原因是我想向我继承的Argument Parser 添加额外的“命令”。

【问题讨论】:

    标签: python python-3.x argparse subparsers


    【解决方案1】:

    您希望添加的子解析器有什么样的行为?

    sp = parser.add_subparsers(...)
    

    add_subparsers 创建_SubParsersAction 类的位置参数,并在parser._subparsers 属性中记录它。如果该属性已设置,则会引发该错误。 spAction 对象。

    从逻辑上讲,拥有多个“子解析器”操作是没有意义的。当主解析器遇到子解析器命令时,它将解析委托给该子解析器。除了一些清理错误检查之外,主解析器不会恢复解析。所以它无法处理第二个子解析器命令。

    add_subparsers 创建的术语和 add_parser 所做的术语可能会令人困惑。一个是位置参数/Action,另一个是解析器(ArgumentParser 的实例)。

    应该可以将新的解析器添加到现有的subparsers Action(我必须尝试找到一种干净的方法)。也可以添加嵌套子解析器,即为子解析器定义add_subparsers


    parents 方法绕过了 thismultiple subparser arguments 测试,可能是因为它第一次没有设置parser._subparsers 属性(从父级复制操作时)。这样实际上创建了两个subparser arguments。这就是help 显示的内容。但我的猜测是解析将没有意义。它仍然会期待“original_subparser”,而不是寻找“extra”或“extra2”。

    parents 机制不可靠。它有直接的用途,但很容易被破坏。


    In [2]: parser = argparse.ArgumentParser(prog='main')
    In [3]: a1 = parser.add_argument('--foo')
    In [4]: parser._subparsers    # initial value None
    
    In [5]: sp = parser.add_subparsers(dest='cmd')
    In [6]: parser._subparsers    # new non-None value
    Out[6]: <argparse._ArgumentGroup at 0xaf780f0c>
    

    sp 对象,Action 子类:

    In [8]: sp
    Out[8]: _SubParsersAction(option_strings=[], dest='cmd', nargs='A...', const=None, default=None, type=None, choices=OrderedDict(), help=None, metavar=None)
    In [9]: sp1 = sp.add_parser('cmd1')
    

    sp 是一个动作(位置参数); sp1 是一个解析器。

    In [10]: parser.print_help()
    usage: main [-h] [--foo FOO] {cmd1} ...
    
    positional arguments:
      {cmd1}
    
    optional arguments:
      -h, --help  show this help message and exit
      --foo FOO
    

    _actions 属性是一个操作列表。注意helpfoo

    In [12]: parser._subparsers._actions
    Out[12]: 
    [_HelpAction(option_strings=['-h', '--help'], dest='help',...),
     _StoreAction(option_strings=['--foo'], dest='foo',....),
     _SubParsersAction(option_strings=[], dest='cmd', ...]
    

    所以这个列表中的最后一项是sp 对象

    In [13]: parser._subparsers._actions[-1]
    Out[13]: _SubParsersAction(option_strings=[], dest='cmd', nargs='A...', const=None, default=None, type=None, choices=OrderedDict([('cmd1', ArgumentParser(prog='main cmd1', usage=None, description=None, formatter_class=<class 'argparse.HelpFormatter'>, conflict_handler='error', add_help=True))]), help=None, metavar=None)
    

    所以我们可以添加一个新的子解析器

    In [14]: parser._subparsers._actions[-1].add_parser('extra')
    ...
    In [15]: parser.print_help()
    usage: main [-h] [--foo FOO] {cmd1,extra} ...
    
    positional arguments:
      {cmd1,extra}
    
    optional arguments:
      -h, --help    show this help message and exit
      --foo FOO
    

    因此,如果您只想将 extraextra2 添加到 original_subparser,这应该可以。

    只要我们不再尝试parser.add_argument(...),抓住最后一个_actions 项目应该可以工作。如果不是最后一次,我们就必须进行更复杂的搜索。

    从我的rep变化来看,有人发现了这个_subparsers属性的早期探索:

    How to obtain argparse subparsers from a parent parser (to inspect defaults)

    【讨论】:

    • 谢谢。我有点担心在模块内部四处寻找,但这确实似乎是唯一的方法!
    猜你喜欢
    • 1970-01-01
    • 2011-11-21
    • 1970-01-01
    • 2015-12-11
    • 2021-09-16
    • 1970-01-01
    • 1970-01-01
    • 2015-07-17
    • 2015-01-06
    相关资源
    最近更新 更多