Próbuję napisać skrypt, który akceptuje wiele źródeł wejściowych i robi coś z każdym z nich. Coś takiego
./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
Ale nie mogę się do końca dowiedzieć, jak to zrobić za pomocą argparse
. Wygląda na to, że jest skonfigurowany tak, że każdej flagi opcji można użyć tylko raz. Wiem, jak powiązać wiele argumentów z jedną opcją ( nargs='*'
lub nargs='+'
), ale to nadal nie pozwala mi -i
wielokrotnie używać flagi. Jak mam się do tego zabrać?
Żeby było jasne, na koniec chciałbym otrzymać listę list łańcuchów. Więc
[["input1_url", "input1_name", "input1_other"],
["input2_url", "input2_name", "input2_other"],
["input3_url", "input3_name"]]
python
argparse
multiple-arguments
John Allard
źródło
źródło
Odpowiedzi:
Oto parser, który obsługuje powtórzone 2 argumenty opcjonalne - z nazwami zdefiniowanymi w
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']])
To nie załatwia
2 or 3 argument
sprawy (chociaż napisałem jakiś czas temu łatkę na błąd / problem Pythona, który obsługiwałby taki zakres).Co powiesz na oddzielną definicję argumentu z
nargs=3
imetavar=('url','name','other')
?Krotki
metavar
można również używać znargs='+'
inargs='*'
; 2 struny są używane jako[-u A [B ...]]
lub[-u [A [B ...]]]
.źródło
To jest proste; po prostu dodaj oba
action='append'
inargs='*'
(lub'+'
).import argparse parser = argparse.ArgumentParser() parser.add_argument('-i', action='append', nargs='+') args = parser.parse_args()
A kiedy go uruchomisz, otrzymasz
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']]
źródło
-i
powinien być skonfigurowany tak, aby akceptował 3 argumenty i używałappend
akcji.>>> 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']])
Aby obsłużyć opcjonalną wartość, możesz spróbować użyć prostego typu niestandardowego. W tym przypadku argument do
-i
jest pojedynczym łańcuchem rozdzielanym przecinkami, z liczbą podziałów ograniczoną do 2. Konieczne byłoby przetworzenie wartości końcowych, aby upewnić się, że określono co najmniej dwie wartości.>>> 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']])
Aby uzyskać większą kontrolę, zdefiniuj akcję niestandardową. Ten rozszerza wbudowane
_AppendAction
(używane przezaction='append'
), ale po prostu sprawdza zakres liczby argumentów podanych-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)
źródło
inputX_other_var
jest to opcjonalne.