Использование одного и того же параметра несколько раз в 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"]]
4 ответа
Вот синтаксический анализатор, который обрабатывает повторный необязательный аргумент 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 ...]]]
,
Это просто; просто добавьте оба 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']]
-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'
), но просто выполняет проверку диапазона количества аргументов, переданных -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)
Добавление с другим в этой теме.
Если вы используете вadd_argument()
тогда вы будете получать аргументы в списках внутри списка каждый раз, когда добавляете опцию.
Как вам понравилось:
[
["input1_url", "input1_name", "input1_other"],
["input2_url", "input2_name", "input2_other"],
["input3_url", "input3_name"]
]
Но если кому-то нужны эти аргументы в том жеlist[]
, затем используйтеaction='extend'
вместо action='append'
в вашем коде. Это даст вам эти аргументы в одном списке.
[
"input1_url",
"input1_name",
"input1_other",
"input2_url",
"input2_name",
"input2_other",
"input3_url",
"input3_name"
]