2016-03-22 8 views
27

Я пытаюсь написать сценарий, который принимает несколько источников ввода и что-то делает для каждого. Что-то вроде этогоИспользуя ту же опцию несколько раз в Argparse Python

./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"]] 
+0

Так почему бы не связать несколько аргументов источника ввода с этой единственной опцией? – TigerhawkT3

+0

Поскольку каждый из нескольких источников ввода также должен иметь несколько аргументов строки. Я бы хотел использовать флаг -i для каждого из входов, и каждый вход будет содержать все строки между последовательными флагами -i. Я хочу, чтобы он работал как ffmpeg, где вы указываете входные данные с -i –

ответ

32

Вот анализатор, который обрабатывает повторный 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='*'; 2 строки используются как [-u A [B ...]] или [-u [A [B ...]]].

+0

Ничего себе! Мне нравится, как функция help показывает, что представляют собой отдельные компоненты многочастной опции. Я буду использовать это! –

11

-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']]) 

Для обработки необязательного значения вы можете попробовать использовать простой пользовательский тип. В этом случае аргумент -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'), but just does some range checking on the number of arguments given to -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) 
+0

Brilliant! Спасибо за помощь. –

+2

Это не * совершенно * делает то, что вы хотите; Я пропустил, что 'inputX_other_var' является необязательным. – chepner

+0

Я только что вернулся к комментарию как таковой, ваш путь требует всех варов. Это в правильном направлении! –