Python argparse необязательные вложенные аргументы

Я хотел бы иметь аргумент для моей программы, который имеет некоторые обязательные параметры наряду с некоторыми необязательными параметрами. Что-то вроде этого:

[--print text [color [size]]

так что вы можете передать его любой из них:

mycommand --print hello
mycommand --print hello blue
mycommand --print hello red 12

Их может быть несколько, поэтому должен быть один add_argument. Например:

[--print text [color]] [--output filename [overwrite]]

Я могу получить аргументы, близкие к тому, что я хочу:

>>> parser = argparse.ArgumentParser()
>>> act = parser.add_argument('--foo', nargs=3, metavar=('x','y','z'))
>>> act = parser.add_argument('--bar', nargs='?')
>>> act = parser.add_argument('--baz', nargs='*')
>>> parser.print_help()
usage: [-h] [--foo x y z] [--bar [BAR]] [--baz [BAZ [BAZ ...]]]

optional arguments:
  -h, --help            show this help message and exit
  --foo x y z
  --bar [BAR]
  --baz [BAZ [BAZ ...]]

но не совсем. Есть ли способ сделать это с помощью argparse? Я знаю, что могу сделать их все nargs="*", но тогда --help не будет перечислять имена необязательных аргументов. Если я передам nargs="*" и кортеж для metavar, argparse выдаст исключение.


person jterrace    schedule 10.03.2011    source источник


Ответы (4)


Прочитав исходный код (начало в take_action), я понял, что вы хотеть невозможно. Анализ всех аргументов и передача их действиям выполняются на основе nargs, а nargs — это либо число, либо OPTIONAL ("?"), ZERO_OR_MORE ("*"), ONE_OR_MORE ("+"), PARSER или REMAINDER. Это должно быть определено до того, как объект Action (который обрабатывает ввод) даже увидит, что он получает, поэтому он не может динамически определить nargs.

Я думаю, вам придется жить с обходным путем. У меня может быть --foo-x x, --foo-y y и --foo-z z, а может быть и --foo x y z.

person Devin Jeanpierre    schedule 10.03.2011

Как насчет

def printText(args):
  print args

parser = argparse.ArgumentParser()
subparser = parser.add_subparsers()
printer = subparser.add_parser('print')
printer.add_argument('text')
printer.add_argument('color', nargs='?')
printer.add_argument('size', type=int, nargs='?')
printer.set_defaults(func=printText)

cmd = parser.parse_args()
cmd.func(cmd)

Тогда вы получите что-то вроде этого:

$ ./test.py -h
usage: test.py [-h] {print} ...

positional arguments:
  {print}

$ ./test.py print -h
usage: test.py print [-h] text [color] [size]

positional arguments:
  text
  color
  size

$ ./test.py print text
Namespace(color=None, func=<function printText at 0x2a96150b90>, size=None, text='text')

$ ./test.py print text red
Namespace(color='red', func=<function printText at 0x2a96150b90>, size=None, text='text')

$ ./test.py print text red 12
Namespace(color='red', func=<function printText at 0x2a96150b90>, size=12, text='text')
person CNeo    schedule 14.12.2011
comment
Но вы можете указать только один подпарсер одновременно, это не будет работать для нескольких. - person jterrace; 14.12.2011
comment
Можете ли вы привести пример для нескольких? Мой пример сводится к необязательным позиционным аргументам, оба из которых имеют значение nargs='?', поэтому в зависимости от того, что вам нужно сделать, это может быть выполнено без подпарсеров. или несколько подпарсеров .. :) - person CNeo; 16.12.2011
comment
У меня есть пример в моем OP: mycommand --print hello red 12 --output имя файла перезаписать - person jterrace; 16.12.2011
comment
Извините, наверное, мне следовало более четко прочитать вопрос. Вы можете смоделировать то, что вам нужно, с помощью nargs='+' или nargs='*', которые уже настолько близки, насколько вы подошли. metavar действительно может принимать кортеж, но может определять только два имени (а не три). Также вы можете перезаписать справку для чего-то вроде parser.add_argument('--print', nargs='+', metavar=('text', 'color'), help='--print text [color [size]]') - person CNeo; 19.12.2011

Согласно ответу Девина Жанпьера, кажется, что использование «+» (один или несколько) вместо «*» сделает то, чего вы пытаетесь достичь. (PS: я бы просто прокомментировал его ответ, если бы у меня было достаточно очков)

person Siddardha    schedule 22.08.2017
comment
Не забывай, он также не хочет больше трех аргументов. Если вы включите это в свой пост, вы можете опубликовать независимый ответ (если вы, конечно, отдаете должное Жану Пьеру за его идею). - person Alex; 22.08.2017

который будет работать для одного аргумента:

parser.add_argument('--write_google', nargs='?', const='Yes',
                    choices=['force', 'Yes'],
                    help="write local changes to google")
person Lareb Kinsky    schedule 26.04.2013