我有一个合并多个视频和音频文件的脚本。现在我有一个允许四个值的参数:
# -A FILENAME LANGUAGE POSITION SPEED
$ script.py [... more parameters ...] -A audio.mp3 eng -1 1 [... more parameters ...]
现在我希望第三个和第四个是可选的。目前我有两个想法,但也许有更好的解决方案:
nargs
设置为+
并在提供1个或4个以上参数时抛出错误。也许type
参数可以捕获这个。问题是在帮助中看不到需要2到4个值。该参数也可能多次出现(action
为append
)。
答案 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;允许这样做。
告诉用户他们可以提供多少参数。如果代码没有达到您想要的效果,您可以随时提供自定义usage
,description
或help
。
对象,如果他们输入1或超过4.您可以在3个位置测试条目 - 使用自定义type
,自定义action
或parse_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不起作用。