如何从父解析器获取 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.