7

正如文档所示:

argparse.REMAINDER。所有剩余的命令行参数都被收集到一个列表中。这对于调度到其他命令行实用程序的命令行实用程序通常很有用:

>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('--foo')
>>> parser.add_argument('command')
>>> parser.add_argument('args', nargs=argparse.REMAINDER)
>>> print parser.parse_args('--foo B cmd --arg1 XX ZZ'.split())
Namespace(args=['--arg1', 'XX', 'ZZ'], command='cmd', foo='B')

我试图将其用于完全相同的目的,但在某些情况下,这对我来说似乎是错误的(或者我的概念可能是错误的)

import argparse

a = argparse.ArgumentParser()

a.add_argument('-qa', nargs='?')
a.add_argument('-qb', nargs='?')
a.add_argument('rest', nargs=argparse.REMAINDER)

a.parse_args('-qa test ./otherutil bar -q atr'.split())

结果:

test.py: error: ambiguous option: -q could match -qa, -qb

因此,显然,如果otherutil有这样的论点以某种方式与给定的论点“冲突” argparse,它似乎无法正常工作。

我希望当argparse达到REMAINDER那种参数时,它只会用完列表末尾的所有字符串,而无需进一步解析。我能以某种方式达到这种效果吗?

4

4 回答 4

7

我在尝试将选项分派给底层实用程序时遇到了这个问题。我最终使用的解决方案是nargs='*'代替nargs=argparse.REMAINDER,然后只使用“伪参数”--来分隔我的命令和底层工具的选项:

>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--myflag', action='store_true')
>>> parser.add_argument('toolopts', nargs='*')
>>> parser.parse_args('--myflag -- -a --help'.split())
Namespace(myflag=True, toolopts=['-a', '--help'])

这在帮助输出中很容易记录。

于 2018-08-04T15:01:33.000 回答
5

这与处理缩写有关,而不是与 REMAINDER 有关nargs

In [111]: import argparse                                                                 
In [112]: a = argparse.ArgumentParser() 
     ...:  
     ...: a.add_argument('-qa', nargs='?') 
     ...: a.add_argument('-qb', nargs='?')                                                

In [113]: a.parse_args('-qa test ./otherutil bar -q atr'.split())                         
usage: ipython3 [-h] [-qa [QA]] [-qb [QB]]
ipython3: error: ambiguous option: -q could match -qa, -qb

argparse进行 2 遍解析。首先,它尝试将字符串分类为选项(标志)或参数。其次,它在解析位置和可选项之间交替,根据nargs.

这里歧义发生在第一遍。它试图将“-q”与两个可用的选项相匹配。REMAINDER 的特殊动作(吸收 '-q' 就好像它是一个普通的字符串)直到第二遍才发生。

较新argparse的版本允许我们关闭缩写处理:

In [114]: a.allow_abbrev                                                                  
Out[114]: True
In [115]: a.allow_abbrev=False                                                            
In [116]: a.parse_args('-qa test ./otherutil bar -q atr'.split())                         
usage: ipython3 [-h] [-qa [QA]] [-qb [QB]]
ipython3: error: unrecognized arguments: ./otherutil bar -q atr

如果我添加 REMAINDER 动作:

In [117]: a.add_argument('rest', nargs=argparse.REMAINDER) 

In [118]: a.parse_args('-qa test ./otherutil bar -q atr'.split())                         
Out[118]: Namespace(qa='test', qb=None, rest=['./otherutil', 'bar', '-q', 'atr'])

@Colin 建议使用 '--' 有效,因为该字符串在第一遍中被识别:

In [119]: a.allow_abbrev=True                                                             
In [120]: Out[117].nargs='*'                                                              
In [121]: a.parse_args('-qa test -- ./otherutil bar -q atr'.split())                      
Out[121]: Namespace(qa='test', qb=None, rest=['./otherutil', 'bar', '-q', 'atr'])
于 2019-06-17T23:44:13.987 回答
4

您需要使用两个 --.

a.add_argument('--qa', nargs='?')
a.add_argument('--qb', nargs='?')

因此,您定义的选项与 a 冲突-q,它至少接受一个参数,在其他地方定义

来自argparse 文档

ArgumentParser.add_argument(name or flags...)

name or flags - Either a name or a list of option strings, e.g. foo or -f, --foo.

编辑回复@PDani第一条评论:

这个帖子很有趣。

据我了解,argparse 遵循 POSIX 和 GNU 风格。

重要的是,短(1 个字母)选项可以组合在一起,如果一个选项需要一个参数,则可以将其附加到选项字母上。例如,如果你有这样的东西

a.add_argument('-a', action='store_true')
a.add_argument('-b', action='store_true')
a.add_argument('-c', action='store_true')
a.add_argument('-d', nargs=1)
a.add_argument('-e', nargs=1)

您可以将它们称为-abcd3 -e5or -a -b -c -d3 -e5or -cba -e5 -d3, ...
现在,如果您有

a.add_argument('-abc',  action='store_true')

argparse 很难确定-abc是附加了 3 个短参数还是一个长参数。因此,您被迫将参数定义为--abc.

所以我猜你不能使用长参数 name 和 one -

我知道一种叫做docopt的命令行解析的替代方法:你可以看看,但我怀疑它是否能解决你的问题。

于 2013-03-18T15:08:26.147 回答
4

也许是一些特殊处理的组合ArgumentParser.parse_known_args()和其他一些特殊处理?

这并不完美,但可能会导致正确的方向:

import argparse
import sys

a = argparse.ArgumentParser()
# treat the common-prefixed arguments as options to the prefix
a.add_argument("-q")

# allow a delimiter to set off your arguments from those which should go to the
# other utility, and use parse_known_args() if the delimiter is not present
argv = sys.argv[1:]
if "--" in argv:
    i = argv.index("--")
    args, extra = a.parse_args(argv[:i]), argv[i + 1:]
else:
    a.add_argument("extra", nargs=argparse.REMAINDER)
    args, _ = a.parse_known_args(argv)
    extra = args.extra

# complain if the `-q` option was not specified correctly
if args.q not in ("something", "otherthing"):
    a.error("Must specify '-qsomething' or '-qotherthing'")

print "q:", "-q%s" % (args.q,)
print "extra:", '"%s"' % (" ".join(extra),)

结果:

$ ./testcmd -qsomething test ./otherutil bar -q atr
q: -qsomething
extra: "test ./otherutil bar -q atr"

注意事项:

  1. 这将在-prefixed 选项-q的其余部分和其余部分之间留出空格。-q
  2. 这将消耗一个-q选项,但如果指定更多选项,我不记得它是否会引发异常(或做任何其他有用的事情)。
于 2015-12-14T21:48:36.240 回答