Argparse:如果子解析器的选项均共享父项,则它们将覆盖主要选项 [英] Argparse: options for subparsers override main if both share parent

查看:31
本文介绍了Argparse:如果子解析器的选项均共享父项,则它们将覆盖主要选项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用带有几个子解析器的argparse.我希望我的程序在args中的任何位置(包括子解析器)都采用详细级别的选项.

I'm using argparse with several subparsers. I want my program to take options for verbosity anywhere in the args, including the subparser.

from argparse import ArgumentParser
p = ArgumentParser()
p.add_argument('--verbose', '-v', action='count')

sub = p.add_subparsers()
a = sub.add_parser('a')

print(p.parse_args())

默认情况下,如果用于子解析器,则主解析器的选项将引发错误:

By default, options for the main parser will throw an error if used for subparsers:

$ python tmp.py -v a
Namespace(verbose=1)

$ python tmp.py a -v
usage: tmp.py [-h] [--verbose] {a} ...
tmp.py: error: unrecognized arguments: -v

我从此答案中调查了父解析器.

I looked into parent parsers, from this answer.

from argparse import ArgumentParser

parent = ArgumentParser(add_help=False)
parent.add_argument('--verbose', '-v', action='count')

main = ArgumentParser(parents=[parent])

sub = main.add_subparsers()
a = sub.add_parser('a', parents=[parent])

print(main.parse_args())

但是由于某些原因,所有共享标志都不能在主解析器上工作.

For some reason though, none of the shared flags work on the main parser.

$ python tmp2.py a -vvv
Namespace(verbose=3)
$ python tmp2.py -vvv a
Namespace(verbose=None)

请注意,主解析器肯定具有适当的参数,因为当我将其更改为main = ArgumentParser()时,会得到error: unrecognized arguments: -v.我在这里想念什么?

Note that the main parser definitely has the appropriate arguments, because when I change it to main = ArgumentParser() I get error: unrecognized arguments: -v. What am I missing here?

推荐答案

首先,一些一般性意见.

First, a couple of general comments.

主解析器处理输入直到子解析器调用,然后调用子解析器并给定其余的argv.完成后,它的namespace被合并回主namespace.

The main parser handles the input upto the subparser invocation, then the subparser is called and given the remaining argv. When it is done, it's namespace is merged back into the the main namespace.

parents机制通过引用从parent复制动作.因此,您的主解析器和子解析器共享相同的verbose Action对象.当子解析器尝试设置其他默认值或帮助时,这就是一个问题.在这里可能不是问题,但请记住这一点.

The parents mechanism copies Actions from the parent by reference. So your main and subparsers share the same verbose Action object. That's been a problem when the subparser tries to set a different default or help. It may not be an issue here, but just keep it in mind.

即使没有parents机制,在主解析器和子解析器之间共享dest或options标志也可能很棘手.是否应使用子解析器操作的默认值?如果两者都使用怎么办?子解析器会覆盖主解析器的操作吗?

Even without the parents mechanism, sharing a dest or options flag between main and subparser can be tricky. Should the default of the subparser Action be used? What if both are used? Does the subparser overwrite the main parser's actions?

最初,主namespace传递给了子解析器,该子解析器对其进行了修改并返回.前一阵子改变了(如果需要,我可以找到错误/问题).现在,子解析器以默认的空namespace开头,将其填充.然后将这些值合并到主要值中.

Originally the main namespace was passed to the subparser, which it modified and returned. This was changed a while back (I can find the bug/issue if needed). Now the subparser starts with a default empty namespace, fills it. And these values are then merged into the main.

因此,在链接的SO问题中,请警惕较早的答案.从那时起argparse可能已更改.

So in your linked SO question, be wary of older answers. argparse may have changed since then.

我认为您的情况是主解析器和子解析器verbose分别计数.当您得到None时,这就是您看到的子解析器的默认设置.

I think what's happening in your case is that the main and subparser verbose are counting separately. And when you get None it's the subparser's default that you see.

_Count_Action__call__是:

def __call__(self, parser, namespace, values, option_string=None):
    new_count = _ensure_value(namespace, self.dest, 0) + 1
    setattr(namespace, self.dest, new_count)

我怀疑在较旧的argparse中,当共享名称空间时,count会是累积的,但是如果不重新创建较旧的样式subparser动作类,我将无法对其进行测试.

I suspect that in older argparse when the namespace was shared, the count would have been cumulative, but I can't test it without recreating an older style subparser action class.

https://bugs.python.org/issue15327 -原始开发人员建议在此处提供两个不同的dest参数.记录来自主和子的输入.然后,如果需要,您自己的代码可以合并结果.

https://bugs.python.org/issue15327 - here the original developer suggests giving the two arguments different dest. That records the inputs from both main and sub. Your own code can then merge the results if needed.

https://bugs.python.org/issue27859 argparse - subparsers does not retain namespace.在这里,我建议一种重新创建较旧样式的方法.

https://bugs.python.org/issue27859 argparse - subparsers does not retain namespace. Here I suggest a way of recreating the older style.

https://bugs.python.org/issue9351 argparse set_defaults on subcommands should override top level set_defaults-这是问题在2014年改变了名称空间的使用.

https://bugs.python.org/issue9351 argparse set_defaults on subcommands should override top level set_defaults - this is the issue in 2014 that changed the namespace use.

这篇关于Argparse:如果子解析器的选项均共享父项,则它们将覆盖主要选项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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