这里已经有一些有用的答案,但我想要更多:用逗号分隔,使用choices 验证值,并获得有用的错误消息,所以下面我提供了一个解决方案。
简单版
作为第一遍,我们可以将适当的函数传递给type 参数:
>>> import argparse
>>> parser = argparse.ArgumentParser(prog='cmd')
>>> parser.add_argument('--foo', type=lambda arg: arg.split(','))
>>> parser.parse_args(['--foo', 'a,b,c'])
Namespace(foo=['a', 'b', 'c'])
但这不适用于choices,因为它会检查整个列表是否在选择中,而不是每个值:
>>> parser = argparse.ArgumentParser(prog='cmd')
>>> parser.add_argument('--foo', type=lambda arg: arg.split(','), choices=('a', 'b', 'c'))
>>> parser.parse_args(['--foo', 'a,b,c'])
usage: cmd [-h] [--foo {a,b,c}]
cmd: error: argument --foo: invalid choice: ['a', 'b', 'c'] (choose from 'a', 'b', 'c')
将nargs 设置为* 或+ 之类的值会检查每个值,但仅适用于以空格分隔的参数(例如--foo a b)而不是逗号分隔的参数。如果我们自己生成列表,似乎没有支持的方法来检查每个值是否在选项中。因此,我们需要通过type 参数(如 Shiplu Mokaddim partially implemented)自己提出错误。创建自定义 Action 类听起来很有希望,因为动作可以访问选项,但是动作发生在 type 函数应用并检查值之后,所以我们仍然无法使用 @987654335 add_argument() 上的 @ 参数用于此目的。
更好的版本
这是使用自定义type 函数的解决方案。我们这个函数接受一个有效选择的列表,但是由于类型转换的函数只能接受一个参数字符串,我们需要将它包装在一个类中(并定义特殊的__call__() 方法)或函数闭包。本解决方案使用后者。
>>> def csvtype(choices):
... """Return a function that splits and checks comma-separated values."""
... def splitarg(arg):
... values = arg.split(',')
... for value in values:
... if value not in choices:
... raise argparse.ArgumentTypeError(
... 'invalid choice: {!r} (choose from {})'
... .format(value, ', '.join(map(repr, choices))))
... return values
... return splitarg
>>> parser = argparse.ArgumentParser(prog='cmd')
>>> parser.add_argument('--foo', type=csvtype(('a', 'b', 'c')))
>>> parser.parse_args(['--foo', 'a,b,c'])
Namespace(foo=['a', 'b', 'c'])
>>> parser.parse_args(['--foo', 'a,b,d'])
usage: cmd [-h] [-f F]
cmd: error: argument -f: invalid choice: 'd' (choose from 'a', 'b', 'c')
请注意,我们也会收到相应的错误。为此,请务必在函数内使用argparse.ArgumentTypeError 而不是argparse.ArgumentError。
其他选项
用户 wim suggested 上面未讨论的其他一些选项。由于以下原因,我不认为这些具有吸引力:
解析后对参数进行后处理意味着您必须做更多工作才能使错误消息与来自argparse 的错误消息保持一致。只需提高argparse.ArgumentError 就会导致堆栈跟踪。此外,argparse 会捕获解析期间出现的错误并更改它们以指定所使用的选项,否则您需要手动执行。
子类化ArgumentParser 工作量更大,convert_arg_line_to_args() 用于从文件而非命令行读取参数。