如何从父解析器获取 argparse 子解析器(检查默认值) [英] How to obtain argparse subparsers from a parent parser (to inspect defaults)

查看:33
本文介绍了如何从父解析器获取 argparse 子解析器(检查默认值)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我创建了一个带有参数默认值的解析器,然后给它一个带有参数默认值的子解析器.

Suppose that I create a parser with a default value for an argument, and then give it a subparser with a further default value for an argument.

In [1]: parser = argparse.ArgumentParser(description='test')

In [2]: parser.add_argument("--test", dest="test", default="hello")
Out[2]: _StoreAction(option_strings=['--test'], dest='test', nargs=None, const=None, default='hello', type=None, choices=None, help=None, metavar=None)

In [3]: parser.get_default("test")
Out[3]: 'hello'

In [4]: subparsers = parser.add_subparsers(dest="command")

In [5]: parser_other = subparsers.add_parser("other")

In [6]: parser_other.add_argument("--other-test", dest="other_test", default="world")
Out[6]: _StoreAction(option_strings=['--other-test'], dest='other_test', nargs=None, const=None, default='world', type=None, choices=None, help=None, metavar=None)

In [7]: parser_other.get_default("other_test")
Out[7]: 'world'

这一切都很好.但是假设我有一个函数从上面创建并返回父解析器 parser,但不能直接访问子解析器.

This is all fine. But suppose that I have a function which creates and returns the parent parser parser from above, but with no direct access to the subparser.

我怎样才能打印出子解析器参数的默认值?或者分别获取每个子解析器的句柄?

How can I still print out defaults for the subparser arguments? Or get a handle to each subparser separately?

In [8]: parser._subparsers._defaults
Out[8]: {}

In [9]: parser._subparsers.get_default("other_test")  # is None

似乎没有更多来自 parser._subparsers 或来自 parser 的属性或方法可以显示默认值.

There doesn't appear to be any more attributes or methods from parser._subparsers or from parser that could display defaults.

总体问题是:当您只有父解析器的句柄时,如何以编程方式访问子解析器默认值?

The overall problem is: how to programmatically access subparser defaults when you only have a handle to the parent parser?

推荐答案

你说得对.但也许我可以解释一些细节.

You got it right. But maybe I can explain a few details.

a = parser.add_argument(...)

add_argument 创建一个 Action 对象(或者实际上是一个取决于 action 参数的子类).您可以在自己的环境中保存指向该对象的指针.但该操作也收集在 parse._actions 列表中.这就是 parser 跟踪其参数的方式.

add_argument creates an Action object (or actually a subclass depending on the action parameter). You can save a pointer to that object in your own environment. But that Action is also collected in the parse._actions list. That's how the parser keeps tracks of its arguments.

阅读_actions 应该总是安全的.修改它有破坏解析器的风险.argument_groups 可以访问列表.

Reading _actions should always be safe. Modifying it risks breaking breaking the parser. argument_groups have access to the list.

subparsers = parser.add_subparsers(dest="command")

add_argument 的特殊版本,创建并返回一个 argparse._SubParsersAction 对象.subparsers 就是那个对象.正如前面的答案所指出的,您可以通过搜索正确的子类在 _actions 列表中找到它.(对于主解析器,subparsers 只是另一个位置参数.)

is a specialized version of add_argument, creating and returning a argparse._SubParsersAction object. subparsers is that object. And as noted from the earlier answer, you can find it in the _actions list by searching for the correct subclass. (To the main parser, subparsers is just another positional argument.)

subparsers 维护自己的 parsers 专用字典,可作为其 choices 属性访问.主解析器没有这些子解析器的任何记录.

subparsers maintains its own specialized dictionary of parsers, accessible as its choices attribute. The main parser does not have any record of those sub parsers.

parser_other = subparsers.add_parser("other")

创建一个解析器,将其放入那个 choices 映射中,并返回一个供您自己使用的引用(使用 add_argument 等).每个子解析器都有自己的 _actions 列表.(以及它自己的 _defaults).

creates a parser, puts it in that choices map, and returns a reference for your own use (with add_argument etc). Each sub parser has its own _actions list. (and its own _defaults).

查看get_defaults方法的代码:

def get_default(self, dest):
    for action in self._actions:
        if action.dest == dest and action.default is not None:
            return action.default
    return self._defaults.get(dest, None)

它使用 _actions 属性.并查看 Action 的 action.default 属性.

It uses the _actions attribute. And looks at the action.default attribute of the Action.

self._defaults 是由 parser.set_defaults 方法更新的字典.该方法还将其参数复制到相关的 Action 对象.get_defaults 检查是否 dest 是未绑定到特定操作的默认值之一.https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.set_defaults

self._defaults is the dictionary updated by the parser.set_defaults method. That method also copies its parameters to the relevant Action objects. get_defaults checks that in case the dest is one of those defaults that isn't tied to a particular Action. https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.set_defaults

我很少使用 parser._subparsers 属性.查看 parser.add_subparsers 方法,我发现它实际上是一个 argument_group.Argument_groups 主要是一个 help 工具,用于对帮助行进行分组.解析器对象与其argument_groups 之间的关系有点棘手,可能不是您想要使用的.

I haven't used the parser._subparsers attribute much. Looking at the parser.add_subparsers method I see it is actually an argument_group. Argument_groups are primarily a help tool, used to group help lines. The relationship between a parser object and its argument_groups is a little tricky, and probably not something you want to use.

这是一个例子,有更多(太多)细节:

Here's an example, with more (too much) detail:

In [22]: parser = argparse.ArgumentParser()
In [23]: sp = parser.add_subparsers(title='subparsers', dest='cmd')
In [24]: sp1 = sp.add_parser('cmd1')
In [25]: sp2 = sp.add_parser('cmd2')
In [26]: parser.print_help()
usage: ipython3 [-h] {cmd1,cmd2} ...

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

subparsers:
  {cmd1,cmd2}

In [28]: [a.dest for a in parser._actions]
Out[28]: ['help', 'cmd']

In [29]: parser._action_groups
Out[29]: 
[<argparse._ArgumentGroup at 0xaf86bf2c>,
 <argparse._ArgumentGroup at 0xaf86bdcc>,
 <argparse._ArgumentGroup at 0xac99fa6c>]
In [30]: [g.title for g in parser._action_groups]
Out[30]: ['positional arguments', 'optional arguments', 'subparsers']

In [31]: parser._subparsers
Out[31]: <argparse._ArgumentGroup at 0xac99fa6c>

_subparsers_defaults实际上和parser._defaults是同一个字典

The _defaults of _subparsers is actually the same dictionary as parser._defaults

In [32]: parser.set_defaults(extra='foobar')
In [33]: parser._defaults
Out[33]: {'extra': 'foobar'}
In [34]: parser._subparsers._defaults
Out[34]: {'extra': 'foobar'}

parser._subparsers._actions 也与 parser._actions 相同.但该组确实维护自己的列表操作(用于帮助显示).

parser._subparsers._actions is also identical to parser._actions. But the group does maintain its own list actions (used in the help display).

In [35]: parser._subparsers._group_actions
Out[35]: [_SubParsersAction(option_strings=[], dest='cmd', nargs='A...', const=None, 
    default=None, type=None, choices=OrderedDict([...]), help=None, metavar=None)]

因此您可以使用 parser._subparsers._group_actions[0] 来查找 subparsers 操作对象,而不是搜索 parsers._actions 列表.

So you could use parser._subparsers._group_actions[0] to find the subparsers action object instead of searching the parsers._actions list.

In [37]: parser._subparsers._group_actions[0].choices
Out[37]: 
OrderedDict([('cmd1',
              ArgumentParser(prog='ipython3 cmd1', usage=None, description=None,...)),
             ('cmd2',
              ArgumentParser(prog='ipython3 cmd2', usage=None, description=None,...))])

再想一想,parser._subparsers._group_actions 可能没那么有用.如果你不给它一个特殊的标题,那么它就等同于 parser._positionals,所有位置参数的参数组.所以你仍然需要验证 _SubParsersAction 类.

On second thought, parser._subparsers._group_actions might not be so useful. If you don't give it a special title, then it is identical to parser._positionals, the argument group of all positional arguments. So you'd still need to verify the _SubParsersAction class.

这篇关于如何从父解析器获取 argparse 子解析器(检查默认值)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆