argparse 的逗号分隔输入而不是空格分隔输入

Cam*_*o21 5 python command-line-arguments

我正在使用argparse从命令行接收输入来运行我的脚本。

我当前的输入字符串如下所示:

path> python <\filename\\> -t T1 T2 T3 -f F1 F2
Run Code Online (Sandbox Code Playgroud)

argparse 中是否有一个参数,而不是按空格分隔输入,我可以用逗号分隔它们?

换句话说:

path> python <\filename\\> -t T1,T2,T3 -f F1,F2
Run Code Online (Sandbox Code Playgroud)

wim*_*wim 5

中没有这样的功能argparse

备择方案:

  • 后处理args命名空间并手动拆分/解析值
  • 定义自定义action并手动拆分/解析值
  • 定义自定义type并手动拆分/解析值
  • 子类化ArgumentParser和自定义ArgumentParser.convert_arg_line_to_args


goo*_*ami 5

这里已经有一些有用的答案,但我想要更多:用逗号分割、使用 验证值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'])
Run Code Online (Sandbox Code Playgroud)

但这不起作用,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')
Run Code Online (Sandbox Code Playgroud)

设置nargs为类似*or 的+值会检查每个值,但仅适用于空格分隔的参数(例如,--foo a b),而不适用于逗号分隔的参数。如果我们自己生成列表,似乎没有受支持的方法来检查每个值是否在选择中。因此,我们需要通过type参数自己引发错误(Shiplu Mokaddim已部分实现)。创建自定义Action类听起来很有希望,因为操作可以访问选择,但操作发生在函数应用并检查值之后type,因此我们仍然无法为此目的使用choices参数 on 。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')
Run Code Online (Sandbox Code Playgroud)

请注意,我们也收到了相应的错误。为此,请确保在函数内部使用argparse.ArgumentTypeErrorand 。argparse.ArgumentError

其他选项

用户 wim建议了一些上面未讨论的其他选项。我不认为这些有吸引力,原因如下:

  • 解析后对参数进行后处理意味着您必须做更多的工作才能使错误消息与argparse. 仅仅提高argparse.ArgumentError就会导致堆栈跟踪。此外,argparse还捕获解析期间引发的错误并更改它们以指定所使用的选项,否则您需要手动执行此操作。

  • 子类化ArgumentParser需要更多工作,并且convert_arg_line_to_args()用于从文件而不是命令行读取参数。