argparse.REMAINDER 更改位置参数的行为

argparse.REMAINDER changes the behavior of positional arguments

没有argparse.REMAINDER,可选参数可以在位置参数之前或之后:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-a')
parser.add_argument('b')

print(parser.parse_args('-a 1 2'.split()))  # Namespace(a='1', b='2')
print(parser.parse_args('2 -a 1'.split()))  # Namespace(a='1', b='2')

但是对于argparse.REMAINDER,可选参数必须在前面:

parser.add_argument('c', nargs=argparse.REMAINDER)

print(parser.parse_args('-a 1 2 3'.split()))  # Namespace(a='1', b='2', c=['3'])
print(parser.parse_args('2 -a 1 3'.split()))  # Namespace(a=None, b='2', c=['-a', '1', '3'])

如何在使用 argparse.REMAINDER 的情况下正确解析最后一行?

来自文档:

argparse.REMAINDER. All the remaining command-line arguments are gathered into a list. This is commonly useful for command line utilities that dispatch to other command line utilities:

这意味着根据定义使用余数在接受这个的参数之后不能有(任何)其他参数,因为它们是余数的一部分,并且会进入这个参数。

为了补充 kabanus 的答案,了解一些参数的解析方式可能会有所帮助。

它遍历参数,首先寻找位置,然后是可选,然后是位置,...,

在位置步骤,它尝试尽可能多地匹配,使用 nargs 作为主要因素。默认是一个字符串(你的'b'); '*' 将匹配到下一个可选的(-a);但是 REMAINDER 会忽略该约束并匹配到最后。所以 'positionals' 评估是贪婪的,而带有 REMAINDER 的评估特别贪婪。

所以在'2 -a 1 3'的情况下,开头的'2'可以匹配'b',其余的可以匹配'c'。仅一个 'positionals' 评估就消耗了整个列表,包括“-a”,并且完成了。

文档示例显示了这一点:

>>> print(parser.parse_args('--foo B cmd --arg1 XX ZZ'.split()))
Namespace(args=['--arg1', 'XX', 'ZZ'], command='cmd', foo='B')

“--foo”被视为可选,但“--arg1”是剩余部分的一部分。 'args'在'command'后立即填充。

如果您想保留对何时使用 REMAINDER 的控制权,请将其设为可选,add_argument('-c',nargs='...')。否则你将受制于这个 positionals/optionals 循环。

顺便说一下,子解析器是用 narg=argarse.PARSER 实现的,它是“+...”的名称。它类似于 REMAINDER 但至少需要一个字符串(子解析器名称)。它也消耗了它路径上的所有东西。

您可能想使用“*”并使用“--”来触发 'consume everything else' 操作,而不是 REMAINDER。