argparse中的nargs范围

时间:2014-04-19 15:55:51

标签: python argparse

我有一个合并多个视频和音频文件的脚本。现在我有一个允许四个值的参数:

# -A FILENAME LANGUAGE POSITION SPEED
$ script.py [... more parameters ...] -A audio.mp3 eng -1 1 [... more parameters ...]

现在我希望第三个和第四个是可选的。目前我有两个想法,但也许有更好的解决方案:

  • nargs设置为+并在提供1个或4个以上参数时抛出错误。也许type参数可以捕获这个。问题是在帮助中看不到需要2到4个值。
  • 所有组合都有4个不同的参数。这将允许位置可选。问题是我需要四个参数名称。

该参数也可能多次出现(actionappend)。

3 个答案:

答案 0 :(得分:1)

我建议-A使用单个逗号分隔的字符串(或使用您选择的分隔符),并为帮助消息提供自定义元变量。

def av_file_type(str):
    data = tuple(str.split(","))
    n = len(data)
    if n < 2:
        raise ArgumentError("Too few arguments")
    elif n == 2:
        return data + (default_position, default_speed)
    elif n == 3:
        return data + (default_speed,)
    elif n == 4:
        return data
    else:
        return ArgumentError("Too many arguments")

p.add_argument("-A", action='append', type=av_file_type,
               metavar='filename,language[,position[,speed]]')

使用nargs='+',按照您喜欢的方式格式化帮助字符串将非常简单。

答案 1 :(得分:1)

我认为你想要发生的事情是:

  • 允许用户输入2,3或4个参数。 &#39; +&#39;允许这样做。

  • 告诉用户他们可以提供多少参数。如果代码没有达到您想要的效果,您可以随时提供自定义usagedescriptionhelp

  • 对象,如果他们输入1或超过4.您可以在3个位置测试条目 - 使用自定义type,自定义actionparse_args之后。< / p>

type在这里没有帮助你,因为它分别处理每个参数。如果我输入p.parse_args('-A one two three'.split()),则type函数被调用3次,每个参数字符串一次。它没有看到所有的字符串。

action可能会有效,因为它会看到parse_args认为-A想要的所有参数值。这将是一个-A和下一个-A(或其他标志)之间的所有字符串。但是,由于您要追加,您需要在argparse._AppendAction类上建模自定义操作。

事后检查namespace可能是您的最佳选择。您将拥有一个列表列表,您可以检查每个子列表中的元素数量。您可以使用parse.error(your_message)生成argparse样式消息。

有关启用nargs范围值http://bugs.python.org/issue11354的Python错误问题。我提出了一个接受nargs='{m,n}'的补丁,该补丁以re功能为模型。事实上,它最终使用re匹配分配的字符串到各种操作。如果您想了解更多关于SethMMorton所谈论的内容,请阅读该问题。

答案 2 :(得分:0)

根据chepner的回答,我开发了一个更先进的“subparser”:

audio_parameters = [ "f", "l", "p", "s", "b", "o" ]
def audio_parser(value):
    data = {
        "l": None,
        "p": -1, 
        "s": 1,
        "b": None,
        "o": 0,
    }   
    found = set()
    if value[0] in audio_parameters and value[1] == "=":
        start = 0 
        while start >= 0:
            end = start
            parameter = value[start]
            found.add(parameter)
            #search for the next ',x=' block, where x is an audio_parameter
            while end >= 0:
                # try next ',' after the last found
                end = value.find(",", end + 2)
                # exit loop, when find, (or after non found)
                if end >= 0 and value[end + 1] in audio_parameters and value[end + 1] not in found and value[end + 2] == "=":
                    end += 1
                    break
            if parameter in audio_parameters:
                parameter_value = value[start + 2:end - 1 if end > 0 else len(value)]
                if parameter_value != "":
                    data[parameter] = parameter_value
                start = end 
    else:
        i = 0 
        for splitted in value.split(","):
        if i >= len(audio_parameters):
            return ArgumentTypeError("Too many arguments")
        if len(splitted) > 0:
            data[audio_parameters[i]] = splitted
        i += 1
    if "f" in data:
        return data
    else:
        raise argparse.ArgumentTypeError("Too few arguments")

这允许建议的file[,lang[,pos[,speed]]],但也可以更高级地选择特定值。例如,仅设置文件,语言和速度f=file,s=speed,l=lang确实有效,并且这可以按任何顺序进行。它还允许看起来像参数名称但不存在或已经使用过的东西。两者都可能已被简单版本(f=file,x=stillname,s=speed,l=lang)解析。然后f参数为file,x=stillname。它还允许f=file,f=overwrites之类的东西,因为它只接受第一次出现。因此,如果文件名包含,b=,您只需编写b=,f=file,b=haha

file,l=lang这样的混合模式是不可能的。正如您可能已经看到的那样,该参数变得更加复杂,现在有6个子参数,这使得几乎不可能为每个组合使用一个参数名称。像'{n,m}'这样的结构也不够灵活,因为你不能轻易省略值。

我注意到一件事,带有[]的metavar不起作用。