python - 如何向 argpare 解析器添加更多子解析器?

标签 python python-3.x argparse subparsers

如果我的代码调用一个返回 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 添加额外的“命令”我继承了它。

最佳答案

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

sp = parser.add_subparsers(...)

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

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

(add_subparsers 创建的内容和 add_parser 执行的术语可能会令人困惑。一个是位置参数/操作,另一个是解析器( ArgumentParser 的实例)。

应该可以向现有的 subparsers 添加新的解析器行动(我必须尝试找到一种干净的方法来做到这一点)。还可以添加嵌套子解析器,即定义 add_subparsers对于子解析器。

<小时/>

那个parents方法绕过了这个multiple 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是一个 Action(位置参数); 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属性是操作列表。请注意help ,和foo

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

所以如果你想添加 extraextra2original_subparser ,这应该可行。

所以只要我们不进一步尝试 parser.add_argument(...)捕获最后_actions项目应该有效。如果这不是最后一次,我们就必须进行更复杂的搜索。

从我的代表变更来看,有人发现了对_subparsers的早期探索。属性:

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

关于python - 如何向 argpare 解析器添加更多子解析器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47113138/

相关文章:

python - 为什么我的 sklearn 自定义转换器在 ColumnTransformer 中使用时不保存属性?

python - 简洁灵活的结构体定义

Python 3 : Calling a Function from a class, self

python - 在 argparse 中指定浮点列表

python - 如何通过 argparse 将 n 长的参数列表添加到标志中?

python - 扭曲的海螺试验 TDD, "StringTransport instance has no attribute..."

python-3.x - 如何在 Pytorch 中使用 KNN、随机森林模型?

python-3.x - 传递变量 python 3 和 html

带有换行的 Python argparse.RawTextHelpFormatter

python - 使用 virtualenv 安装 django1.7 和 Python 3.4