接受固定数量的参数,或者使用固定数量的默认值不接受参数
Accept fixed number of arguments, or no arguments using a fixed number of defaults
我想允许 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
我的问题是,(如何)可以在没有额外代码的情况下完成。 IE。我想找到比这个解决方法更优雅、更默认的 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_argument
的 default
参数中的项目数量推断。这里有一些例子:
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
中返回其余的供您处理。 argparse
处理那些 extras
。使用固定 nargs
处理位置是最简单的。一个带有变量 nargs
的位置通常可以正常工作,但很难使用多个。如果您使用 *
指定了两个操作,解析器应该如何分配字符串?
是的,您可以定义自定义 Action
类 来处理特殊情况,但通常结果不如更简单的 post-解析检查那么优雅 (IMO)。我不给聪明加分:)
我想允许 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
我的问题是,(如何)可以在没有额外代码的情况下完成。 IE。我想找到比这个解决方法更优雅、更默认的 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_argument
的 default
参数中的项目数量推断。这里有一些例子:
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
中返回其余的供您处理。 argparse
处理那些 extras
。使用固定 nargs
处理位置是最简单的。一个带有变量 nargs
的位置通常可以正常工作,但很难使用多个。如果您使用 *
指定了两个操作,解析器应该如何分配字符串?
是的,您可以定义自定义 Action
类 来处理特殊情况,但通常结果不如更简单的 post-解析检查那么优雅 (IMO)。我不给聪明加分:)