Подтвердить что ты не робот

Используя ту же опцию несколько раз в Python Argparse

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

./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"]]
4b9b3361

Ответ 1

Здесь синтаксический анализатор, который обрабатывает повторяющийся аргумент 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 ...]]].

Ответ 2

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