带有可选子命令的 argparse 不能按预期工作

argparse with optional subcommands not working as expected

使用 python 版本 3.9.5 我遇到以下代码片段的问题:

import argparse


parser = argparse.ArgumentParser()

subparsers = parser.add_subparsers(required=False)
sub_parser = subparsers.add_parser("sub")

parser.add_argument("global-argument")

args = parser.parse_args()

运行 python 示例没有参数,导致以下错误消息:

$ python3 main.py
usage: main.py [-h] {sub} ... global-argument
main.py: error: the following arguments are required: global-argument

错误信息显示只有全局参数是必需的,子命令是可选的。

但是 运行 使用全局参数的 python 示例导致以下错误消息:

$ python3 main.py global
usage: main.py [-h] {sub} ... global-argument
main.py: error: invalid choice: 'global' (choose from 'sub')

所以如果没有子命令(应该是可选的)就不可能提供全局参数?

parsersubparsers 是一个 positional 参数,global-argument 也是。 positionals 按照定义的顺序进行解析。但是由于parsing遇到的时候是传递给subparser,而不是传递回main,所以'global-argument'无论如何都可以处理

之后可以为 parser 定义 optional,但那是因为 optionals 是按用户提供的顺序处理的。

parsersubparsers 只是一种特殊的 positional,它将解析任务传递给另一个解析器。 sub_parser 在调用时处理剩余的字符串,而 returns 一个 namespace 并入主 namespaceparser 不恢复解析。

所以主要解析器的参数都应该首先定义,并首先在命令行中使用。 subparser(s) 和参数在此之后定义和使用。

最初 subparsers 不是可选的,因为 positionals 是正常的(没有特殊的 nargs)。但是,作为更改 'required' 参数的测试和标记方式的意外副作用,默认情况下 subparsers 变成了不需要的。我们已经处理了一段时间的后果。

我投票最多的答案与此有关; Argparse with required subparser

此外,包含一个 dest 也是一个好主意,既可以更好地识别使用了哪个子解析器,也可以防止错误消息中出现问题。

subparsers = parser.add_subparsers(dest='cmd')