Argparse: обов'язкові аргументи, перелічені у розділі "необов'язкові аргументи"?


229

Я використовую наступний простий код для розбору деяких аргументів; зауважте, що один із них потрібен. На жаль, коли користувач запускає скрипт, не надаючи аргумент, відображений текст використання / довідки не вказує на наявність необов'язкового аргументу, який я вважаю дуже заплутаним. Як я можу отримати python, щоб вказати, що аргумент не є обов'язковим?

Ось код:

import argparse
if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description='Foo')
    parser.add_argument('-i','--input', help='Input file name', required=True)
    parser.add_argument('-o','--output', help='Output file name', default="stdout")
    args = parser.parse_args()
    print ("Input file: %s" % args.input )
    print ("Output file: %s" % args.output )

Під час запуску вище коду без надання необхідного аргументу, я отримую такий висновок:

usage: foo.py [-h] -i INPUT [-o OUTPUT]

Foo

optional arguments:
    -h, --help            show this help message and exit
    -i INPUT, --input INPUT
                          Input file name
    -o OUTPUT, --output OUTPUT
                          Output file name

5
У рядку використання -i INPUTдеталь не оточена квадратними дужками, що тонкості вказує на те, що дійсно потрібно. Також ви можете вручну пояснити, що через helpпарам
Хайме RGP

7
@JaimeRGP Так, але це, звичайно, недостатньо, і це також менш видно. Присвоєне ім’я групи optional argumentsдля необхідних аргументів все ще вводить в оману.
Акумен

Відповіді:


316

Параметри, що починаються з -або --зазвичай вважаються необов’язковими. Усі інші параметри є позиційними параметрами і як такі вимагаються конструкцією (як аргументи позиційної функції). Можна вимагати необов'язкові аргументи, але це трохи суперечить їх дизайну. Оскільки вони все ще є частиною непозиційних аргументів, вони все ще будуть перераховані під заплутаним заголовком "необов'язкові аргументи", навіть якщо вони потрібні. Однак відсутні частини квадратних дужок у частині використання показують, що вони дійсно потрібні.

Дивіться також документацію :

Взагалі модуль argparse передбачає, що прапори типу -f і --bar вказують необов'язкові аргументи, які завжди можна опустити в командному рядку.

Примітка. Обов'язкові параметри, як правило, вважаються поганою формою, оскільки користувачі очікують, що варіанти будуть необов'язковими, і тому їх слід уникати, коли це можливо.

При цьому, заголовки "позиційні аргументи" та "необов'язкові аргументи" у довідці породжуються двома групами аргументів, в яких аргументи автоматично розділяються. Тепер ви можете "зламати" та змінити назву необов'язкових, але набагато більш елегантним рішенням буде створити іншу групу для "необхідних іменованих аргументів" (або як би ви їх хотіли назвати):

parser = argparse.ArgumentParser(description='Foo')
parser.add_argument('-o', '--output', help='Output file name', default='stdout')
requiredNamed = parser.add_argument_group('required named arguments')
requiredNamed.add_argument('-i', '--input', help='Input file name', required=True)
parser.parse_args(['-h'])
usage: [-h] [-o OUTPUT] -i INPUT

Foo

optional arguments:
  -h, --help            show this help message and exit
  -o OUTPUT, --output OUTPUT
                        Output file name

required named arguments:
  -i INPUT, --input INPUT
                        Input file name

У мене було те саме питання. Я спробував вам рішення. Це додає аргументи до нової групи, але мій код, здається, не працює після цього. Будь-які рішення будуть вдячні. Посилання на мій код - pastebin.com/PvC2aujz
Zarar Mahmud

1
@ZararMahmud: Ви вводите порожні аргументи у рядку 24 вашого коду: parser.parse_args([])Натомість використовуйте parser.parse_args()без аргументів для збору вмісту sys.argv. За аргументацією
Девін

@poke: Приємне рішення! Але це не допомагає у випадку, якщо вам потрібні взаємні ексклюзивні групи, чи я щось пропускаю?
Суддя

@Judge я рекомендував би прочитати цей pymotw.com/3/argparse/#mutual-exclusive-options
Пітер Мур

79

Оскільки я вважаю за краще перелічити необхідні аргументи перед необов'язковим, я рублю його через:

    parser = argparse.ArgumentParser()
    parser._action_groups.pop()
    required = parser.add_argument_group('required arguments')
    optional = parser.add_argument_group('optional arguments')
    required.add_argument('--required_arg', required=True)
    optional.add_argument('--optional_arg')
    return parser.parse_args()

і це виводи:

usage: main.py [-h] [--required_arg REQUIRED_ARG]
               [--optional_arg OPTIONAL_ARG]

required arguments:
  --required_arg REQUIRED_ARG

optional arguments:
  --optional_arg OPTIONAL_ARG

Я можу жити без "допомоги", показуючи необов'язкову групу аргументів.


3
Чи насправді це змушує аргументацію ставитися до будь-якого з аргументів як потрібно?
Ентоні

6
Я думаю, що аргумент "необхідний" все-таки потрібно встановити, додаючи аргумент.
Карл Розан

Це справді приємно.
Пол Сезанн

7
@Anthony - для цього вам не потрібно 'обов’язково = Істинно' у add_argument. Наведена відповідь ілюструє групування аргументів.
користувач2275693

47

Будівництво від @Karl Rosaen

parser = argparse.ArgumentParser()
optional = parser._action_groups.pop() # Edited this line
required = parser.add_argument_group('required arguments')
# remove this line: optional = parser...
required.add_argument('--required_arg', required=True)
optional.add_argument('--optional_arg')
parser._action_groups.append(optional) # added this line
return parser.parse_args()

і це виводи:

usage: main.py [-h] [--required_arg REQUIRED_ARG]
           [--optional_arg OPTIONAL_ARG]

required arguments:
  --required_arg REQUIRED_ARG

optional arguments:
  -h, --help                    show this help message and exit
  --optional_arg OPTIONAL_ARG

1
BTW, чи існують способи (способи), як отримати доступ _action_groupбез доступу до захищеного члена? У моєму випадку мені потрібно додати якийсь аргумент до вже існуючої (спеціальної) групи.
Machin

Це чудово. Вирішує елемент --help, який відображається у другому додатковому списку.
Джеремі

Примітка : ця відповідь порушує відкритий API, перевірте відповідь Bryan_D нижче.
lol

18

Ще один раз, розбудовуючи @RalphyZ

Цей не порушує відкритий API.

from argparse import ArgumentParser, SUPPRESS
# Disable default help
parser = ArgumentParser(add_help=False)
required = parser.add_argument_group('required arguments')
optional = parser.add_argument_group('optional arguments')

# Add back help 
optional.add_argument(
    '-h',
    '--help',
    action='help',
    default=SUPPRESS,
    help='show this help message and exit'
)
required.add_argument('--required_arg', required=True)
optional.add_argument('--optional_arg')

Який буде показувати те саме, що вище, і має пережити майбутні версії:

usage: main.py [-h] [--required_arg REQUIRED_ARG]
           [--optional_arg OPTIONAL_ARG]

required arguments:
  --required_arg REQUIRED_ARG

optional arguments:
  -h, --help                    show this help message and exit
  --optional_arg OPTIONAL_ARG

Чи можете ви пояснити, як відповідь RalphyZ порушує відкритий API?
jeremysprofile

5
_action_groupsпризначений лише для внутрішнього використання. Тому не існує гарантії сумісності для різних версій.
Bryan_D
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.