Требуется простой пример argparse: 1 аргумент, 3 результата


529

Документация для argparse модуля питона , в то время как отлично я уверен, это слишком много для меня крошечный начинающего мозга , чтобы понять прямо сейчас. Мне не нужно делать математику в командной строке или вмешиваться в форматирование строк на экране или изменять параметры символов. Все, что я хочу сделать, это «Если arg - A, сделайте это, если B сделает это, если ни один из вышеперечисленных не показывает помощь и выход» .


15
тогда просто проверьте sys.argvаргумент, который вы хотите ...
JBernardo

10
Вы когда-нибудь пробовали plac ? Это простая в использовании оболочка над argparse с отличной документацией .
kirbyfan64sos

157
это не ты. это argparse. он пытается отвезти вас в путешествие к звездам, и ему все равно, куда вы направлялись.
Флориан Хейгл

11
Сумасшедшие "питонические" API снова: /
mlvljr

69
Благослови тебя, Мэтт Вилки, за то, что ты заступался за крошечные мозги для начинающих повсюду.
полька

Ответы:


255

Мое понимание исходного вопроса двоякое. Во-первых, с точки зрения простейшего возможного примера argparse, я удивлен, что не видел его здесь. Конечно, чтобы быть простым, это также накладные расходы с небольшой силой, но это может помочь вам начать.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("a")
args = parser.parse_args()

if args.a == 'magic.name':
    print 'You nailed it!'

Но этот позиционный аргумент теперь необходим. Если вы пропустите это при вызове этой программы, вы получите ошибку об отсутствующих аргументах. Это приводит меня ко второй части оригинального вопроса. Мэтт Вилки, кажется, хочет один дополнительный аргумент без именованной метки (метки --option). Мое предложение будет изменить приведенный выше код следующим образом:

...
parser.add_argument("a", nargs='?', default="check_string_for_empty")
...
if args.a == 'check_string_for_empty':
    print 'I can tell that no argument was given and I can deal with that here.'
elif args.a == 'magic.name':
    print 'You nailed it!'
else:
    print args.a

Возможно, есть более элегантное решение, но оно работает и является минималистским.


4
После некоторого размышления я делаю вывод, что этот вопрос на самом деле лучше всего отвечает на вопрос в том виде, в котором он задан, и на затруднительное положение, в котором я находился в то время. Другие отличные ответы собрали более чем достаточно представителей, чтобы доказать свою ценность и могут выдержать небольшую конкуренцию. :-)
Matt Wilkie

@badnack: Это то, что вы хотите, что бы это ни было. Если вы ожидаете один аргумент, например имя файла, это то, что было введено как имя файла в командной строке. Затем вы можете выполнить свою собственную обработку, чтобы определить, существует ли она в файловой системе, но это еще один вопрос и ответ.
Mightypile

363

Вот как я это делаю argparse(с несколькими аргументами):

parser = argparse.ArgumentParser(description='Description of your program')
parser.add_argument('-f','--foo', help='Description for foo argument', required=True)
parser.add_argument('-b','--bar', help='Description for bar argument', required=True)
args = vars(parser.parse_args())

args будет словарь, содержащий аргументы:

if args['foo'] == 'Hello':
    # code here

if args['bar'] == 'World':
    # code here

В вашем случае просто добавьте только один аргумент.


3
как уже упоминалось в моем комментарии к другому ответу, я хотел бы сохранить автоматическое форматирование справки argparse, но, похоже, нет возможности использовать аргумент без имени (скорее всего, я просто не понимаю его, когда вижу его ), например, нужно делать foo.py --action installили foo.py --action removeвместо этого простоfoo.py install
Matt Wilkie

7
@mattwilkie Затем вы должны определить позиционный аргумент, например: parser.add_argument('install', help='Install the app') (Обратите внимание, что вы не можете определить позиционный аргумент с помощью required=True)
Диего Наварро

32
Как новичок в argparse, этот ответ действительно помог, потому что я не знал, где найти варианты после того, как они были переданы . Другими словами, мне нужно было понять, как argsбыл создан диктат, как указано выше.
mrKelley

3
Используйте «короткую форму» при вызове программы непосредственно из командной строки и «длинную форму» при запуске программы / команды в скрипте. В этом случае он удобнее для чтения с длинной формой и, следовательно, легче следовать логике кода / сценария.
Оля

17
Лично я считаю более понятным доступ к аргументам как args.fooи args.barвместо синтаксиса словаря. В любом случае это нормально, но args - это не словарь, а argparse.Namespaceобъект.
Майкл Миор

210

argparseДокументация достаточно хорошо , но оставляет несколько полезных деталей , которые не могут быть очевидны. (@Diego Navarro уже упоминал кое-что из этого, но я постараюсь немного расширить его ответ.) Основное использование выглядит следующим образом:

parser = argparse.ArgumentParser()
parser.add_argument('-f', '--my-foo', default='foobar')
parser.add_argument('-b', '--bar-value', default=3.14)
args = parser.parse_args()

Возвращаемый вами объект parse_args()- это объект «Пространство имен»: объект, переменные-члены которого названы в соответствии с аргументами командной строки. NamespaceОбъект как получить доступ к аргументам и значению , связанное с ними:

args = parser.parse_args()
print args.my_foo
print args.bar_value

(Обратите внимание, что argparseв именах аргументов «-» заменяется подчеркиванием при именовании переменных.)

Во многих ситуациях вы можете использовать аргументы просто как флаги, которые не имеют значения. Вы можете добавить их в argparse следующим образом:

parser.add_argument('--foo', action='store_true')
parser.add_argument('--no-foo', action='store_false')

Выше будут созданы переменные с именем 'foo' со значением True и 'no_foo' со значением False соответственно:

if (args.foo):
    print "foo is true"

if (args.no_foo is False):
    print "nofoo is false"

Также обратите внимание, что вы можете использовать опцию «required» при добавлении аргумента:

parser.add_argument('-o', '--output', required=True)

Таким образом, если вы пропустите этот аргумент в командной строке, argparseон сообщит вам, что он отсутствует, и остановит выполнение вашего скрипта.

Наконец, обратите внимание, что с помощью функции можно создать сложную структуру ваших аргументов vars, если это облегчит вам жизнь.

args = parser.parse_args()
argsdict = vars(args)
print argsdict['my_foo']
print argsdict['bar_value']

Как вы видете, vars возвращает dict с именами аргументов в качестве ключей и их значениями в качестве значений.

Есть много других опций и вещей, которые вы можете сделать, но это должно охватывать наиболее важные, распространенные сценарии использования.


3
Какой смысл '-f'и '-b'? Почему ты не можешь опустить это?
user2763361

13
Довольно условно иметь как «короткую форму» (одна черта), так и «длинную форму» (две черты) для каждой опции времени выполнения. Вы увидите это, например, почти в каждой стандартной утилите Unix / Linux; сделайте man cpили, man lsи вы обнаружите, что много вариантов входят в обоих вариантах (например -f, --force). Вероятно, существуют различные причины, по которым люди предпочитают одну или другую, но в любом случае достаточно стандартно сделать обе формы доступными в вашей программе.
DMH

59

Мэтт спрашивает о позиционных параметрах в argparse, и я согласен, что в документации по Python по этому аспекту не хватает. На ~ 20 нечетных страницах нет ни одного полного примера, показывающего как синтаксический анализ, так и использование позиционных параметров .

Ни один из других ответов здесь не показывает полный пример позиционных параметров, так что вот полный пример:

# tested with python 2.7.1
import argparse

parser = argparse.ArgumentParser(description="An argparse example")

parser.add_argument('action', help='The action to take (e.g. install, remove, etc.)')
parser.add_argument('foo-bar', help='Hyphens are cumbersome in positional arguments')

args = parser.parse_args()

if args.action == "install":
    print("You asked for installation")
else:
    print("You asked for something other than installation")

# The following do not work:
# print(args.foo-bar)
# print(args.foo_bar)

# But this works:
print(getattr(args, 'foo-bar'))

Меня поразило то, что argparse преобразует именованный аргумент "--foo-bar" в "foo_bar", но позиционный параметр с именем "foo-bar" остается как "foo-bar", что делает его менее очевидным, как используйте это в своей программе.

Обратите внимание на две строки в конце моего примера - ни одна из них не сработает, чтобы получить значение позиционного параметра foo-bar. Первое явно неверно (это арифметическое выражение args.foo минус бар), но второе тоже не работает:

AttributeError: 'Namespace' object has no attribute 'foo_bar'

Если вы хотите использовать foo-barатрибут, вы должны использовать getattr, как показано в последней строке моего примера. Сумасшествие заключается в том, что если вы попытаетесь dest=foo_barизменить имя свойства на что-то более простое, вы получите действительно странное сообщение об ошибке:

ValueError: dest supplied twice for positional argument

Вот как работает приведенный выше пример:

$ python test.py
usage: test.py [-h] action foo-bar
test.py: error: too few arguments

$ python test.py -h
usage: test.py [-h] action foo-bar

An argparse example

positional arguments:
  action      The action to take (e.g. install, remove, etc.)
  foo-bar     Hyphens are cumbersome in positional arguments

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

$ python test.py install foo
You asked for installation
foo

5
nargs='?'это заклинание для «необязательного позиционирования» согласно stackoverflow.com/questions/4480075/…
MarkHu

Тот факт, что позиционный элемент foo-barне преобразован, foo_barрассматривается в bugs.python.org/issue15125 .
hpaulj

2
Я думаю, что более простой обходной путь для этой ошибки - просто вызвать аргумент "foo_bar" вместо "foo-bar", тогда он print args.foo_barработает. Поскольку это позиционный аргумент, вам не нужно указывать имя при вызове скрипта, поэтому для пользователя это не имеет значения.
Луатор

@luator Вы правы, аргумент легко переименовать, но автор отчета об ошибке убедительно доказывает, что это все-таки ошибка, из-за ненужной когнитивной нагрузки. При использовании argparse необходимо приостановить и вспомнить различные соглашения об именах для параметров и аргументов. См. Bugs.python.org/msg164968 .
Марк Э. Хаас

1
@ mehaase Я полностью согласен с тем, что это ошибка, которая должна быть исправлена. Я просто думаю, что переименование аргумента - это более простой и менее запутанный обходной путь, чем необходимость его использования getattr(он также более гибок, так как позволяет изменять аргумент с необязательного на позиционный без изменения кода, использующего значение).
Луатор

22

Еще одно краткое введение, вдохновленное этим постом .

import argparse

# define functions, classes, etc.

# executes when your script is called from the command-line
if __name__ == "__main__":

    parser = argparse.ArgumentParser()
    #
    # define each option with: parser.add_argument
    #
    args = parser.parse_args() # automatically looks at sys.argv
    #
    # access results with: args.argumentName
    #

Аргументы определяются с помощью следующих комбинаций:

parser.add_argument( 'name', options... )              # positional argument
parser.add_argument( '-x', options... )                # single-char flag
parser.add_argument( '-x', '--long-name', options... ) # flag with long name

Общие варианты:

  • help : описание этого аргумента при --helpиспользовании.
  • default : значение по умолчанию, если аргумент опущен.
  • Тип : если вы ожидаете floatили int(иначе str).
  • dest : присвоить флагу другое имя (например '-x', '--long-name', dest='longName').
    Примечание: по умолчанию --long-nameдоступ осуществляется сargs.long_name
  • действие : для специальной обработки определенных аргументов
    • store_true, store_false: для логических аргументов
      '--foo', action='store_true' => args.foo == True
    • store_const: для использования с опциейconst
      '--foo', action='store_const', const=42 => args.foo == 42
    • count: для повторных вариантов, как в./myscript.py -vv
      '-v', action='count' => args.v == 2
    • append: для повторных вариантов, как в./myscript.py --foo 1 --foo 2
      '--foo', action='append' => args.foo == ['1', '2']
  • требуется : если флаг требуется, или позиционный аргумент - нет.
  • Наргс : для флага захватить N арг
    ./myscript.py --foo a b => args.foo = ['a', 'b']
  • выбор : ограничить возможные входные данные (указать в виде списка строк или целых, если type=int).

12

Обратите внимание на учебник по Argparse в Python HOWTO . Это начинается с большинства основных примеров, таких как этот:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
                    help="display a square of a given number")
args = parser.parse_args()
print(args.square**2)

и прогрессирует до менее основных.

Есть пример с предопределенным выбором для опции, например, что спрашивается:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
                    help="display a square of a given number")
parser.add_argument("-v", "--verbosity", type=int, choices=[0, 1, 2],
                    help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbosity == 2:
    print("the square of {} equals {}".format(args.square, answer))
elif args.verbosity == 1:
    print("{}^2 == {}".format(args.square, answer))
else:
    print(answer)

Приятно видеть, что документы были обновлены. Уверяю вас, это был не тот случай, когда ОП опубликовал вопрос 5 лет назад.
ntwrkguru

10

Вот что я придумал в своем учебном проекте, в основном благодаря @DMH ...

Демо-код:

import argparse

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-f', '--flag', action='store_true', default=False)  # can 'store_false' for no-xxx flags
    parser.add_argument('-r', '--reqd', required=True)
    parser.add_argument('-o', '--opt', default='fallback')
    parser.add_argument('arg', nargs='*') # use '+' for 1 or more args (instead of 0 or more)
    parsed = parser.parse_args()
    # NOTE: args with '-' have it replaced with '_'
    print('Result:',  vars(parsed))
    print('parsed.reqd:', parsed.reqd)

if __name__ == "__main__":
    main()

Это, возможно, развивалось и доступно онлайн: command-line.py

Скрипт для тренировки этого кода: command-line-demo.sh


2
Напоследок пример argparse, который имеет смысл
opentokix

5

Вы также можете использовать plac (обертку вокруг argparse).

В качестве бонуса он генерирует аккуратные справочные инструкции - см. Ниже.

Пример скрипта:

#!/usr/bin/env python3
def main(
    arg: ('Argument with two possible values', 'positional', None, None, ['A', 'B'])
):
    """General help for application"""
    if arg == 'A':
        print("Argument has value A")
    elif arg == 'B':
        print("Argument has value B")

if __name__ == '__main__':
    import plac
    plac.call(main)

Пример вывода:

Аргументы не предоставлены - example.py :

usage: example.py [-h] {A,B}
example.py: error: the following arguments are required: arg

Неожиданный аргумент предоставлен - example.py C :

usage: example.py [-h] {A,B}
example.py: error: argument arg: invalid choice: 'C' (choose from 'A', 'B')

Правильный аргумент предоставлен - example.py A :

Argument has value A

Меню полной справки (генерируется автоматически) - example.py -h :

usage: example.py [-h] {A,B}

General help for application

positional arguments:
  {A,B}       Argument with two possible values

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

Краткое объяснение:

Имя аргумента обычно равно имени параметра ( arg).

Аннотация кортежа после argпараметра имеет следующее значение:

  • Описание ( Argument with two possible values)
  • Тип аргумента - один из 'flag', 'option' или 'positional' ( positional)
  • Сокращение ( None)
  • Тип значения аргумента - например. float, string ( None)
  • Ограниченный набор вариантов ( ['A', 'B'])

Документация:

Чтобы узнать больше об использовании plac, ознакомьтесь с его великолепной документацией:

Plac: легкий анализ командной строки


4

Чтобы добавить к тому, что заявили другие:

Мне обычно нравится использовать параметр 'dest', чтобы указать имя переменной, а затем использовать 'globals (). Update ()', чтобы поместить эти переменные в глобальное пространство имен.

Применение:

$ python script.py -i "Hello, World!"

Код:

...
parser.add_argument('-i', '--input', ..., dest='inputted_variable',...)
globals().update(vars(parser.parse_args()))
...
print(inputted_variable) # Prints "Hello, World!"

Внутренне argparseиспользует getattrи setattrдля доступа к значениям в пространстве имен. Таким образом, это не беспокоит странно сформированные destценности.
hpaulj

1

Действительно простой способ использования argparse и изменения ключей '-h' / '--help' для отображения ваших собственных справочных инструкций по коду - установить для справки по умолчанию значение False, вы также можете добавить столько дополнительных .add_arguments, сколько пожелаете. :

import argparse

parser = argparse.ArgumentParser(add_help=False)

parser.add_argument('-h', '--help', action='help',
                help='To run this script please provide two arguments')
parser.parse_args()

Запустите: python test.py -h

Вывод:

usage: test.py [-h]

optional arguments:
  -h, --help  To run this script please provide two arguments

-1

Самый простой ответ!

PS тот, кто написал документ argparse, глуп

код Python:

import argparse
parser = argparse.ArgumentParser(description='')
parser.add_argument('--o_dct_fname',type=str)
parser.add_argument('--tp',type=str)
parser.add_argument('--new_res_set',type=int)
args = parser.parse_args()
o_dct_fname = args.o_dct_fname
tp = args.tp
new_res_set = args.new_res_set

бегущий код

python produce_result.py --o_dct_fname o_dct --tp father_child --new_res_set 1

Этот ответ не добавляет ничего нового / отличного от существующих ответов.
NVS Abhilash

Я самый ясный, говорите дешево, покажите код
gouxute
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.