Argparse:子解析器的选项覆盖 main 如果两者共享父

Jos*_*son 5 python argparse python-3.x

我将 argparse 与几个子解析器一起使用。我希望我的程序在 args 中的任何地方都采用详细程度的选项,包括子解析器。

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())
Run Code Online (Sandbox Code Playgroud)

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

$ 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
Run Code Online (Sandbox Code Playgroud)

我从这个答案中查看了父解析器。

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())
Run Code Online (Sandbox Code Playgroud)

但是由于某种原因,没有一个共享标志在主解析器上工作。

$ python tmp2.py a -vvv
Namespace(verbose=3)
$ python tmp2.py -vvv a
Namespace(verbose=None)
Run Code Online (Sandbox Code Playgroud)

请注意,主分析器肯定有相应的参数,因为当我将其更改为main = ArgumentParser()我得到error: unrecognized arguments: -v。我在这里缺少什么?

hpa*_*ulj 3

首先,有一些一般性评论。

主解析器处理输入直到子解析器调用,然后调用子解析器并给出剩余的argv. 完成后,它namespace会合并回 main 中namespace

parents机制通过引用复制操作parent。所以你的主解析器和子解析器共享相同的verboseAction 对象。当子解析器尝试设置不同的默认值或帮助时,这就是一个问题。这里可能不是问题,但请记住这一点。

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

最初,mainnamespace被传递给子解析器,它修改并返回。这是不久前更改的(如果需要,我可以找到错误/问题)。现在子解析器以默认的空开始namespace,填充它。然后将这些值合并到 main 中。

因此,在您链接的 SO 问题中,请警惕旧的答案。argparse从那时起可能已经改变了。

我认为你的情况发生的是主解析器和子解析器verbose是分开计数的。当你得到None它时,你看到的是子解析器的默认值。

__call__for_Count_Action是:

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

我怀疑在较旧的情况下,argparse当命名空间被共享时,它们count会是累积的,但如果不重新创建旧样式的subparser操作类,我就无法测试它。

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

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

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