允许带有 nargs 的位置命令行参数由标志分隔 [英] Allow positional command-line arguments with nargs to be seperated by a flag
问题描述
我有一个使用 argparse 的程序.它需要 1 个必需的位置参数、1 个可选的位置参数和 1 个标志参数.
I have a program using argparse. It takes 1 required positional argument, 1 optional positional argument, and 1 flag argument.
类似于:
usage: test.py [-h] [-a A] b [c]
所以,我尝试使用这个:
So, I tried using this:
parser = argparse.ArgumentParser()
parser.add_argument('-a')
parser.add_argument('b')
parser.add_argument('c', nargs='?', default=None)
print(parser.parse_args())
对于 test.py B C -a A
和 test.py -a A B C
来说效果很好.
Which works fine for test.py B C -a A
and test.py -a A B C
.
但是当我执行 test.py B -a A C
时,它抛出一个错误:
But when I do test.py B -a A C
, it throws an error:
$ python3 test.py B -a A C
usage: test.py [-h] [-a A] b [c]
test.py: error: unrecognized arguments: C
那么,即使中间有一个标志,我怎样才能让它接受可选的位置参数?
So, how can I get it to accept the optional positional argument to be accepted even if there is a flag in between?
请注意,如果我删除 nargs='?', default=None
,这会起作用,但它不是可选的.nargs='*'
也会出现此问题,但 nargs=N
不会出现此问题(例如 nargs=1
、nargs=2
) 并且对于 nargs='+'
不会发生.nargs=argparse.REMAINDER
使它解析标志作为 c
的一部分 (c = ['-a', 'A', 'C']
, a = None
)
Note that this works if I remove the nargs='?', default=None
, but then it's not optional. The problem also happens with nargs='*'
, but this doesn't happen for nargs=N
(e.g. nargs=1
, nargs=2
) and doesn't happen for nargs='+'
. nargs=argparse.REMAINDER
makes it parse the flags as part of c
(c = ['-a', 'A', 'C']
, a = None
)
推荐答案
这是一个已知问题,包括 SO 和 Python 错误/问题,并且没有简单的修复方法.https://bugs.python.org/issue15112
This is a known issue, both here on SO and Python bug/issues, and doesn't have an easy fix. https://bugs.python.org/issue15112
这是基本解析算法的结果.这会尝试解析位置直到下一个可选项的标志.然后解析标记的选项(以及它需要的多少参数).然后解析下一批仓位等
It's the result of the basic parsing algorithm. This trys to parse positionals up to the next optional's flag. Then parse the flagged option (and however many arguments it needs). Then parse the next batch of positions, etc.
解析器在处理b
的时候,也可以处理c
,即使只有一个字符串.c
什么都不需要.这意味着 c
在第一次处理位置时就会用完".
When the parser handles b
, it can also handle c
, even if there is just one string. c
requires nothing. That means c
gets 'used up' the first time it processes positionals.
In [50]: parser.parse_args(['one'])
Out[50]: Namespace(a=None, b='one', c=None)
In [51]: parser.parse_args(['one','two'])
Out[51]: Namespace(a=None, b='one', c='two')
In [52]: parser.parse_args(['one','-a','1','two'])
usage: ipython3 [-h] [-a A] b [c]
ipython3: error: unrecognized arguments: two
An exception has occurred, use %tb to see the full traceback.
SystemExit: 2
/home/paul/.local/lib/python3.6/site-packages/IPython/core/interactiveshell.py:2971: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D.
warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
In [53]: parser.parse_known_args(['one','-a','1','two'])
Out[53]: (Namespace(a='1', b='one', c=None), ['two'])
随着 c
用完(即使它只是获得默认值),就没有什么可以消耗最后一个字符串了.这是一个额外".
With c
used up (even though it just gets the default), there's nothing to consume the last string. It is an 'extra'.
Python 3.7 添加了一个解析方法来解决这个问题,parse_intermixed_args
.https://docs.python.org/3/library/argparse.html#intermixed-parsing
Python 3.7 has added a parsing method that solves this issue, parse_intermixed_args
. https://docs.python.org/3/library/argparse.html#intermixed-parsing
In [447]: import argparse37
In [448]: p = argparse37.ArgumentParser()
In [449]: p.add_argument('pos1');
In [450]: p.add_argument('-a');
In [451]: p.add_argument('pos2', nargs='?');
In [453]: p.parse_args('1 2 -a foo'.split())
Out[453]: Namespace(a='foo', pos1='1', pos2='2')
In [454]: p.parse_args('1 -a foo 2'.split())
usage: ipython3 [-h] [-a A] pos1 [pos2]
ipython3: error: unrecognized arguments: 2
...
In [455]: p.parse_intermixed_args('1 -a foo 2'.split())
Out[455]: Namespace(a='foo', pos1='1', pos2='2')
In [456]: p.parse_intermixed_args('1 2 -a foo'.split())
Out[456]: Namespace(a='foo', pos1='1', pos2='2')
添加它是为了允许在*"位置的中间标记动作.但最终在这种情况下使用?"行动.请注意文档中的警告;它可能无法处理所有 argparse
功能.
It was added as a way of allowing a flagged Action in the middle of a '*' positional. But ends up working in this case with '?' Actions. Note the caution in the docs; it may not handle all argparse
features.
实际上它停用了 positionals
,执行 parse_known_args
以获取所有 optionals
,然后解析 extras
> 仅使用 位置词
.详见parse_known_intermixed_args
代码.
In effect it deactivates the positionals
, does a parse_known_args
to get all optionals
, and then parses the extras
with just the positonals
. See the code of parse_known_intermixed_args
for details.
这篇关于允许带有 nargs 的位置命令行参数由标志分隔的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!