argparse - 结合父解析器、子解析器和默认值 [英] argparse - Combining parent parser, subparsers and default values

查看:34
本文介绍了argparse - 结合父解析器、子解析器和默认值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在一个脚本中定义不同的子解析器,这两个子解析器都从一个共同的父级继承选项,但具有不同的默认值.但是,它没有按预期工作.

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.

我根据我对代码的了解工作,而不是文档中的任何内容.最近在 Cause Python's argparse to execute action for default 中指出文档没有说明 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

子命令中选项的 argparse 冲突解决程序将关键字参数转换为位置参数

和 Python 错误问题:

and Python bug issue:

http://bugs.python.org/issue22401

对于这个问题和那个问题,一个可能的解决方案是(可选)制作操作的副本,而不是共享参考.这样 option_stringsdefaults 可以在子级中修改而不会影响父级.

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屋!

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