在Python的argparse中多次使用相同的选项


82

我正在尝试编写一个脚本,该脚本接受多个输入源并对每个输入源都执行某项操作。像这样

./my_script.py \
    -i input1_url input1_name input1_other_var \
    -i input2_url input2_name input2_other_var \
    -i input3_url input3_name
# notice inputX_other_var is optional

但是我不太清楚如何使用argparse。似乎已设置好,因此每个选项标志只能使用一次。我知道如何将多个参数与单个选项(nargs='*'nargs='+')关联,但这仍然不允许我-i多次使用该标志。我该如何完成这项工作?

为了清楚起见,我最后想要的是一个字符串列表列表。所以

[["input1_url", "input1_name", "input1_other"],
 ["input2_url", "input2_name", "input2_other"],
 ["input3_url", "input3_name"]]

那么,为什么不将多个输入源参数与此单个选项相关联呢?
TigerhawkT3'3

因为多个输入源中的每个都还需要具有多个字符串参数。我想必须对每个输入使用-i标志,并且每个输入将包含连续的-i标志之间的所有字符串。我希望它像ffmpeg的,你用-i指定的投入工作
约翰·阿拉德

Answers:


96

这是一个解析器,该解析器处理重复的2个可选参数-名称在中定义metavar

parser=argparse.ArgumentParser()
parser.add_argument('-i','--input',action='append',nargs=2,
    metavar=('url','name'),help='help:')

In [295]: parser.print_help()
usage: ipython2.7 [-h] [-i url name]

optional arguments:
  -h, --help            show this help message and exit
  -i url name, --input url name
                        help:

In [296]: parser.parse_args('-i one two -i three four'.split())
Out[296]: Namespace(input=[['one', 'two'], ['three', 'four']])

这不能解决问题2 or 3 argument(尽管我前一段时间写了一个补丁来处理这样的范围的Python错误/问题)。

nargs=3和一个单独的参数定义怎么样metavar=('url','name','other')

元组metavar也可以与nargs='+'nargs='*';一起使用。这两个字符串用作[-u A [B ...]][-u [A [B ...]]]


1
喔不错哟!我喜欢帮助功能如何显示多部分选项的各个组件所代表的内容。我会用这个!
John Allard

47

这很简单;只需同时添加action='append'nargs='*'(或'+')。

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-i', action='append', nargs='+')
args = parser.parse_args()

然后,当您运行它时,您会得到

In [32]: run test.py -i input1_url input1_name input1_other_var -i input2_url i
...: nput2_name input2_other_var -i input3_url input3_name

In [33]: args.i
Out[33]:
[['input1_url', 'input1_name', 'input1_other_var'],
 ['input2_url', 'input2_name', 'input2_other_var'],
 ['input3_url', 'input3_name']]

2
谢谢,正是我所需要的!:D旁注:可能的默认值必须是类型列表/数组,否则Argparse将会失败
Tarwin

22

-i应该配置为接受3个参数并使用append操作。

>>> p = argparse.ArgumentParser()
>>> p.add_argument("-i", nargs=3, action='append')
_AppendAction(...)
>>> p.parse_args("-i a b c -i d e f -i g h i".split())
Namespace(i=[['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']])

要处理可选值,您可以尝试使用简单的自定义类型。在这种情况下,to的参数-i是一个逗号分隔的字符串,分割数限制为2。您需要对这些值进行后处理,以确保至少指定了两个值。

>>> p.add_argument("-i", type=lambda x: x.split(",", 2), action='append')
>>> print p.parse_args("-i a,b,c -i d,e -i g,h,i,j".split())
Namespace(i=[['a', 'b', 'c'], ['d', 'e'], ['g', 'h', 'i,j']])

要获得更多控制,请定义一个自定义操作。这个扩展了内置函数_AppendAction(由所使用action='append'),但是只是对赋予的参数数量进行了一些范围检查-i

class TwoOrThree(argparse._AppendAction):
    def __call__(self, parser, namespace, values, option_string=None):
        if not (2 <= len(values) <= 3):
            raise argparse.ArgumentError(self, "%s takes 2 or 3 values, %d given" % (option_string, len(values)))
        super(TwoOrThree, self).__call__(parser, namespace, values, option_string)

p.add_argument("-i", nargs='+', action=TwoOrThree)

1
辉煌!谢谢您的帮助。
John Allard

2
这并不能完全满足您的要求。我错过了那inputX_other_var是可选的。
chepner

我只是回来发表评论,您的方式需要所有变量。但这是朝正确的方向!
John Allard

1
好的,已更新了几个用于处理可选第3个参数的选项。
chepner
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.