这个问题在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