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

时间:2018-02-09 21:43:21

标签: python command-line-arguments

我使用argsparse从命令行接收输入以运行我的脚本。

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

path> python <\filename\\> -t T1 T2 T3 -f F1 F2

argsparse中是否有参数,以便不用空格分隔输入,我可以用逗号分隔它们?

换句话说:

path> python <\filename\\> -t T1,T2,T3 -f F1,F2

5 个答案:

答案 0 :(得分:2)

这里已经有一些有用的答案,但是我还想要更多:用逗号分割,用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函数适用并检查了值,所以我们仍然无法为此,请使用choices上的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()则用于从文件而不是命令行中读取参数。

答案 1 :(得分:1)

argparse中没有此类功能。

备选方案:

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

答案 2 :(得分:0)

您可以使用模块argparse提取参数,然后用空格替换逗号,并将结果传递给comma_args = shlex.split("-t T1,T2,T3 -f F1,F2") # ['-t', 'T1,T2,T3', '-f', 'F1,F2'] args = [x.replace(","," ") for x in comma_args] # ['-t', 'T1 T2 T3', '-f', 'F1 F2'] parse_args(args) 以进行进一步处理:

{{1}}

答案 3 :(得分:0)

逗号分隔的输入实际上是另一种类型。您所要做的就是定义类型。 在这里,我定义了执行此操作的自定义类型。

class DelimiterSeperatedInput:
  def __init__(self, item_type, separator=','):
    self.item_type = item_type
    self.separator = separator

  def __call__(self, value):
    values = []
    try:
      for val in value.split(self.separator):
         typed_value = self.item_type(val)
         values.append(typed_value)
    except Exception:
      raise ArgumentError("%s is not a valid argument" % value)
    return values

parser.add_argument('-t', type=DelimiterSeperatedInput(str),
                    help='comma separated string values')
parser.add_argument('-f', type=DelimiterSeperatedInput(float, ":"), 
                    help="colon separated floats')

此代码可能无法按原样工作,您可能必须修复。但这只是一个想法。

注意:我可以通过使用__call__list等来简化map函数体。但是那样的话,它就不太可读了。一旦有了想法,就可以用它做很多事情。

答案 4 :(得分:0)

如果您还可以使用逗号分隔的空格,那么它内置于argparse

leave