Python argparse необязательные под-аргументы - PullRequest
10 голосов
/ 10 марта 2011

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

[--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 выдает исключение.

Ответы [ 4 ]

8 голосов
/ 14 декабря 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')
6 голосов
/ 10 марта 2011

Читая исходный код (начните с 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.

1 голос
/ 22 августа 2017

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

0 голосов
/ 26 апреля 2013

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

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