接受固定数量的参数,或者不接受使用固定数量默认值的参数



我想允许2个参数或0个参数,然后返回默认值。我认为这应该做到

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('myargs', nargs=2, default=['foo', 'bar'])

然而,这只会抛出2个参数(因此,默认值永远不会被调用(:

print(parser.parse_args(['a', 'b'])) # 2 arguments accepted
print(parser.parse_args([])) # throws

我的问题是,(如何(在没有额外代码的情况下做到这一点。也就是说,我想找到比这个变通方法更优雅、更默认的argparse

import argparse
def parse(args):
parser = argparse.ArgumentParser()
parser.add_argument('myargs', nargs='*', default=['foo', 'bar'])
a = parser.parse_args(args)
if len(a.myargs) != 2:
raise IOError('Incorrect number of arguments')
return a
print(parse([])) # defaults
print(parse(['a', 'b'])) # 2 arguments accepted
print(parse(['a', 'b', 'c'])) # throws (as excepted)

argparse中,不带前缀的参数(默认前缀为-表示缩写或--表示参数全名(被视为必需参数。所以,如果你想有一个可选的论点,你可以这样做:

parser = argparse.ArgumentParser()
parser.add_argument('--myargs', nargs=2, default=['foo', 'bar'])

在这种情况下,如果您不传递任何参数,它将像预期的那样工作:

print(parser.parse_args([]))
Namespace(myargs=['foo', 'bar'])

另一方面,如果您提供相同的值:

print(parser.parse_args(['--myargs', 'a', 'b']))
Namespace(myargs=['a', 'b'])

如果在myargs:之后传递错误数量的参数,将引发错误

print(parser.parse_args(['--myargs', 'a']))
usage: scratch_2.py [-h] [--myargs MYARGS MYARGS]
<your script name>: error: argument --myargs: expected 2 arguments

另一种(更长的(方法是定义一个自定义操作来解析参数:

class CustomParsePositional(argparse.Action):
"""Action to parse arguments with a custom processing"""
def __init__(self, option_strings, dest, nargs=None, **kwargs):
super().__init__(option_strings, dest, nargs='*', **kwargs)
self._custom_nargs = len(kwargs.get('default', []))
def __call__(self, parser, namespace, values, option_string=None):
if len(values) != self._custom_nargs:
parser.error('Incorrect number of arguments')
namespace.__setattr__(self.dest, values)
parser = argparse.ArgumentParser()
parser.add_argument('myargs', default=['foo', 'bar'], type=str, action=CustomParsePositional)

在这种情况下,期望值的数量由add_argumentdefault参数中的项目数量推断。这里有一些例子:

print(parser.parse_args(['a', 'b']))
print(parser.parse_args([]))
print(parser.parse_args(['a']))

Namespace(myargs=['a', 'b'])
Namespace(myargs=['foo', 'bar'])
usage: scratch_2.py [-h] [myargs [myargs ...]]
<your script name>: error: Incorrect number of arguments

如果您传递3个值,您也会得到一个错误:

print(parser.parse_args(['a', 'b', 'c']))
usage: scratch_2.py [-h] [myargs [myargs ...]]
<your script name>: error: Incorrect number of arguments

简要描述argparse解析的工作原理可能会有所帮助。

值收集在namespace对象中。在解析开始时,default值都被放置在namespace中。然后,当在用户输入中遇到自变量时,将按照add_argument中的指定和namespace中的值进行解析,重写默认值。

当看到标志时,会解析带标志的参数,例如"--foo-bar",但需要像您这样的位置,并采用nargs指定的确切字符串数。在这种情况下,它将使用2个字符串。因此,对于这个定义,default参数是无用的。

对于nargs='*',任何数量的字符串都满足它。0字符串的情况得到特殊处理,并将默认值放在namespace中。

解析后添加检查没有什么特别之处。错误消息可以通过以下方式进行精简:

if len(a.myargs) != 2:
parser.error('Incorrect number of arguments')

optparse这样的旧解析器处理所有标记的参数,并在extras中返回其余参数供您处理。CCD_ 19处理那些CCD_。使用固定nargs处理位置是最简单的。具有变量nargs的一个位置通常工作良好,但很难使用多个。如果用*指定了两个操作,那么解析器应该如何分配字符串?

是的,您可以定义自定义Action类来处理特殊情况,但结果通常不如简单的解析后检查优雅(IMO(。我不为聪明加分:(

最新更新