这个问题在http://bugs.python.org/issue9334中有深入讨论。大部分活动是在 2011 年。我去年添加了一个补丁,但有很多argparse补丁积压。
问题是字符串中的潜在歧义'--env',或者"-s WHATEVER -e COOL STUFF"当它跟随一个带有参数的选项时。
optparse做一个简单的从左到右的解析。第一个--env是带有一个参数的选项标志,因此它使用下一个参数,无论它看起来如何。 argparse,另一方面,循环遍历字符串两次。首先,它将它们分类为“O”或“A”(选项标志或参数)。在第二个循环中,它使用它们,使用re类似的模式匹配来处理变量nargs值。在这种情况下,看起来我们有OO, 两个标志并且没有参数。
使用时的解决方案argparse是确保参数字符串不会与选项标志混淆。此处(以及错误问题中)显示的可能性包括:
--env="--env" # clearly defines the argument.
--env " --env" # other non - character
--env "--env " # space after
--env "--env one two" # but not '--env "-env one two"'
其本身'--env'看起来像一个标志(即使被引用,请参阅sys.argv),但当后面跟着其他字符串时它不是。但是"-env one two"有问题,因为它可以被解析为['-e','nv one two']`'-e' 标志后跟一个字符串(甚至更多选项)。
--也nargs=argparse.PARSER可用于强制argparse将所有后续字符串视为参数。但它们只在参数列表的末尾起作用。
在 issue9334 中有一个建议的补丁来添加args_default_to_positional=True模式。在这种模式下,解析器只将字符串分类为选项标志,如果它可以清楚地将它们与定义的参数匹配。因此 '--env --one' 中的 '--one' 将被归类为参数。但是 '--env --env' 中的第二个 '--env' 仍将被归类为选项标志。
展开相关案例
将 argparse 与以破折号 ("-") 开头的参数值一起使用
parser = argparse.ArgumentParser(prog="PROG")
parser.add_argument("-f", "--force", default=False, action="store_true")
parser.add_argument("-e", "--extra")
args = parser.parse_args()
print(args)
生产
1513:~/mypy$ python3 stack16174992.py --extra "--foo one"
Namespace(extra='--foo one', force=False)
1513:~/mypy$ python3 stack16174992.py --extra "-foo one"
usage: PROG [-h] [-f] [-e EXTRA]
PROG: error: argument -e/--extra: expected one argument
1513:~/mypy$ python3 stack16174992.py --extra "-bar one"
Namespace(extra='-bar one', force=False)
1514:~/mypy$ python3 stack16174992.py -fe one
Namespace(extra='one', force=True)
“-foo one”案例失败,因为-foo被解释为-f标志加上未指定的额外内容。这与允许-fe被解释为的动作相同['-f','-e']。
如果我将 更改nargs为REMAINDER(not PARSER),之后的所有内容都-e被解释为该标志的参数:
parser.add_argument("-e", "--extra", nargs=argparse.REMAINDER)
所有案例都有效。请注意,该值是一个列表。并且不需要引号:
1518:~/mypy$ python3 stack16174992.py --extra "--foo one"
Namespace(extra=['--foo one'], force=False)
1519:~/mypy$ python3 stack16174992.py --extra "-foo one"
Namespace(extra=['-foo one'], force=False)
1519:~/mypy$ python3 stack16174992.py --extra "-bar one"
Namespace(extra=['-bar one'], force=False)
1519:~/mypy$ python3 stack16174992.py -fe one
Namespace(extra=['one'], force=True)
1520:~/mypy$ python3 stack16174992.py --extra --foo one
Namespace(extra=['--foo', 'one'], force=False)
1521:~/mypy$ python3 stack16174992.py --extra -foo one
Namespace(extra=['-foo', 'one'], force=False)
argparse.REMAINDER就像'*',除了它接受后面的所有内容,无论它是否看起来像一个标志。 argparse.PARSER更像是“+”,因为它首先需要一个positional类似的参数。它nargs是subparsers使用的。
记录了这种用法REMAINDER,https://docs.python.org/3/library/argparse.html#nargs