Argparse:子解析器的选项覆盖 main 如果两者共享父 [英] Argparse: options for subparsers override main if both share parent

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

问题描述

我将 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 或选项标志也很棘手.是否应该使用 subparser Action 的默认值?如果两者都使用呢?子解析器是否覆盖主解析器的操作?

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 开始,填充它.然后将这些值合并到 main 中.

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 - 子解析器没有保留命名空间.在这里,我建议一种重新创建旧样式的方法.

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应该覆盖顶级 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:子解析器的选项覆盖 main 如果两者共享父的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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