如何创建具有多个位置参数的 argparse 互斥组? [英] How can I create an argparse mutually exclusive group with multiple positional parameters?

查看:21
本文介绍了如何创建具有多个位置参数的 argparse 互斥组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试解析命令行参数,以便可能出现以下三种可能性:

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_argumentrequired 测试,但产生了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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆