如何创建具有多个位置参数的 argparse 互斥组? [英] How can I create an argparse mutually exclusive group with multiple positional parameters?
问题描述
我正在尝试解析命令行参数,以便可能出现以下三种可能性:
I'm trying to parse command-line arguments such that the three possibilities below are possible:
script
script file1 file2 file3 …
script -p pattern
因此,文件列表是可选的.如果指定了 -p pattern
选项,则命令行上不能有任何其他内容.以使用"格式说,它可能看起来像这样:
Thus, the list of files is optional. If a -p pattern
option is specified, then nothing else can be on the command line. Said in a "usage" format, it would probably look like this:
script [-p pattern | file [file …]]
我认为使用 Python 的 argparse
模块的方法是这样的:
I thought the way to do this with Python's argparse
module would be like this:
parser = argparse.ArgumentParser(prog=base)
group = parser.add_mutually_exclusive_group()
group.add_argument('-p', '--pattern', help="Operate on files that match the glob pattern")
group.add_argument('files', nargs="*", help="files to operate on")
args = parser.parse_args()
但是 Python 抱怨我的位置参数需要是可选的:
But Python complains that my positional argument needs to be optional:
Traceback (most recent call last):
File "script", line 92, in <module>
group.add_argument('files', nargs="*", help="files to operate on")
…
ValueError: mutually exclusive arguments must be optional
但是 argparse 文档 说 "*"
nargs
的参数意味着它是可选的.
But the argparse documentation says that the "*"
argument to nargs
meant that it is optional.
我也找不到任何其他可以解决问题的 nargs
值.我最接近的是使用 nargs="?"
,但这只会抓取一个文件,而不是任何数字的可选列表.
I haven't been able to find any other value for nargs
that does the trick either. The closest I've come is using nargs="?"
, but that only grabs one file, not an optional list of any number.
是否可以使用 argparse
来组合这种参数语法?
Is it possible to compose this kind of argument syntax using argparse
?
推荐答案
简答
将 default
添加到 *
位置
引发错误的代码是,
if action.required:
msg = _('mutually exclusive arguments must be optional')
raise ValueError(msg)
如果我向解析器添加一个 *,我会看到设置了 required
属性:
If I add a * to the parser, I see that the required
attribute is set:
In [396]: a=p.add_argument('bar',nargs='*')
In [397]: a
Out[397]: _StoreAction(option_strings=[], dest='bar', nargs='*', const=None, default=None, type=None, choices=None, help=None, metavar=None)
In [398]: a.required
Out[398]: True
而对于 ?
它将是 False.我将在代码中进一步挖掘以了解差异的原因.它可能是一个错误或被忽视的功能",或者可能有一个很好的理由.可选"位置的一个棘手问题是 no-answer 是一个答案,也就是说,一个空的值列表是有效的.
while for a ?
it would be False. I'll have dig a bit further in the code to see why the difference. It could be a bug or overlooked 'feature', or there might a good reason. A tricky thing with 'optional' positionals is that no-answer is an answer, that is, an empty list of values is valid.
In [399]: args=p.parse_args([])
In [400]: args
Out[400]: Namespace(bar=[], ....)
所以互斥必须有某种方法来区分默认的[]
和真实的[]
.
So the mutually_exclusive has to have some way to distinguish between a default []
and real []
.
现在,如果您希望 argparse
执行互斥测试,我建议使用 --files
,这是一个标记参数而不是位置参数.
For now I'd suggest using --files
, a flagged argument rather than a positional one if you expect argparse
to perform the mutually exclusive testing.
设置位置的required
属性的代码是:
The code that sets the required
attribute of a positional is:
# mark positional arguments as required if at least one is
# always required
if kwargs.get('nargs') not in [OPTIONAL, ZERO_OR_MORE]:
kwargs['required'] = True
if kwargs.get('nargs') == ZERO_OR_MORE and 'default' not in kwargs:
kwargs['required'] = True
所以解决方案是为 *
In [401]: p=argparse.ArgumentParser()
In [402]: g=p.add_mutually_exclusive_group()
In [403]: g.add_argument('--foo')
Out[403]: _StoreAction(option_strings=['--foo'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
In [404]: g.add_argument('files',nargs='*',default=None)
Out[404]: _StoreAction(option_strings=[], dest='files', nargs='*', const=None, default=None, type=None, choices=None, help=None, metavar=None)
In [405]: p.parse_args([])
Out[405]: Namespace(files=[], foo=None)
默认值甚至可以是 []
.解析器能够区分您提供的默认值和未提供的默认值.
The default could even be []
. The parser is able to distinguish between the default you provide and the one it uses if none is given.
哎呀 - default=None
是错误的.它通过了add_argument
和required
测试,但产生了mutual_exclusive 错误.细节在于代码如何区分用户定义的默认值和自动默认值.所以使用除了 None
之外的任何东西.
oops - default=None
was wrong. It passes the add_argument
and required
test, but produces the mutually_exclusive error. Details lie in how the code distinguishes between user defined defaults and the automatic ones. So use anything but None
.
我在文档中没有看到任何关于此的内容.我将不得不检查错误/问题以查看该主题已被讨论.之前也可能出现过这种情况.
I don't see anything in the documentation about this. I'll have to check the bug/issues to see it the topic has been discussed. It's probably come up on SO before as well.
这篇关于如何创建具有多个位置参数的 argparse 互斥组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!