argparse-组合父解析器,子解析器和默认值 [英] argparse - Combining parent parser, subparsers and default values
问题描述
我想在脚本中定义不同的子解析器,两个子解析器均从同一个父级继承选项,但具有不同的默认值.但是,它没有按预期工作.
I wanted to define different subparsers in a script, with both inheriting options from a common parent, but with different defaults. It doesn't work as expected, though.
这就是我所做的:
import argparse
# this is the top level parser
parser = argparse.ArgumentParser(description='bla bla')
# this serves as a parent parser
base_parser = argparse.ArgumentParser(add_help=False)
base_parser.add_argument('-n', help='number', type=int)
# subparsers
subparsers = parser.add_subparsers()
subparser1= subparsers.add_parser('a', help='subparser 1',
parents=[base_parser])
subparser1.set_defaults(n=50)
subparser2 = subparsers.add_parser('b', help='subparser 2',
parents=[base_parser])
subparser2.set_defaults(n=20)
args = parser.parse_args()
print args
当我从命令行运行脚本时,这就是我得到的:
When I run the script from the command line, this is what I get:
$ python subparse.py b
Namespace(n=20)
$ python subparse.py a
Namespace(n=20)
显然,第二个set_defaults
覆盖了父级中的第一个.由于argparse文档中没有任何内容(非常详细),所以我认为这可能是一个错误.
Apparently, the second set_defaults
overwrites the first one in the parent. Since there wasn't anything about it in the argparse documentation (which is pretty detailed), I thought this might be a bug.
是否有一些简单的解决方案?之后,我可以检查args
变量,然后将None
值替换为每个子解析器的预期默认值,但这就是我期望argparse为我做的事情.
Is there some simple solution for this? I could check the args
variable afterwards and replace None
values with the intended defaults for each subparser, but that's what I expected argparse to do for me.
顺便说一下,这是Python 2.7.
This is Python 2.7, by the way.
推荐答案
set_defaults
循环遍历解析器的操作,并设置每个default
属性:
set_defaults
loops through the actions of the parser, and sets each default
attribute:
def set_defaults(self, **kwargs):
...
for action in self._actions:
if action.dest in kwargs:
action.default = kwargs[action.dest]
您的-n
自变量(action
对象)是在定义base_parser
时创建的.使用parents
创建每个子解析器时,该操作将添加到每个子解析器的._actions
列表中.它没有定义新的动作;它只是复制指针.
Your -n
argument (an action
object) was created when you defined the base_parser
. When each subparser is created using parents
, that action is added to the ._actions
list of each subparser. It doesn't define new actions; it just copies pointers.
因此,当您在subparser2
上使用set_defaults
时,需要为此共享操作修改default
.
So when you use set_defaults
on subparser2
, you modify the default
for this shared action.
此操作可能是subparser1._action
列表中的第二项(h
是第一项).
This Action is probably the 2nd item in the subparser1._action
list (h
is the first).
subparser1._actions[1].dest # 'n'
subparser1._actions[1] is subparser2._actions[1] # true
如果第二条语句为True
,则意味着两个列表中都包含相同的action
.
If that 2nd statement is True
, that means the same action
is in both lists.
如果您为每个子解析器分别定义了-n
,则不会看到此内容.他们会有不同的动作对象.
If you had defined -n
individually for each subparser, you would not see this. They would have different action objects.
我是根据我对代码的了解而工作的,而不是文档中的任何内容.最近在由于Python的argparse默认执行操作中指出,该文档对add_argument
返回Action
的内容一无所知目的.这些对象是代码组织的重要组成部分,但在文档中却没有得到太多关注.
I'm working from my knowledge of the code, not anything in the documentation. It was pointed out recently in Cause Python's argparse to execute action for default that the documentation says nothing about add_argument
returning an Action
object. Those objects are an important part of the code organization, but they don't get much attention in the documentation.
如果使用解决"冲突处理程序,则通过引用复制父操作也会产生问题,并且需要重用父操作.这个问题是在
Copying parent actions by reference also creates problems if the 'resolve' conflict handler is used, and the parent needs to be reused. This issue was raised in
和Python错误问题:
and Python bug issue:
http://bugs.python.org/issue22401
针对此问题的一种可能的解决方案是(可选)制作操作的副本,而不是共享引用.这样,可以在子级中修改option_strings
和defaults
而不影响父级.
A possible solution, for both this issue and that, is to (optionally) make a copy of the action, rather than share the reference. That way the option_strings
and defaults
can be modified in the children without affecting the parent.
这篇关于argparse-组合父解析器,子解析器和默认值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!