Начиная с версии Python 2.7, в набор стандартных библиотек была включена библиотека argparse для обработки аргументов (параметров, ключей) командной строки. Хотелось бы остановить на ней Ваше внимание.
Для начала рассмотрим, что интересного предлагает argparse.
Argparse — это изящный инструмент для:
Одним из аргументов противников включения argparse в Python был довод о том, что в стандартных модулях и без этого содержится две библиотеки для семантической обработки (парсинга) параметров командной строки. Однако, как заявляют разработчики argparse, библиотеки getopt и optparse уступают argparse по нескольким причинам:
Для начала работы с argparse необходимо задать парсер:
Далее, парсеру стоит указать, какие объекты Вы от него ждете. В частном случае, это может выглядеть так:
Если действие (action) для данного аргумента не задано, то по умолчанию он будет сохраняться (store) в namespace, причем мы также можем указать тип этого аргумента (int, boolean и тд). Если имя возвращаемого аргумента (dest) задано, его значение будет сохранено в соответствующем атрибуте namespace.
В нашем случае:
Простой пример программы, возводящей в квадрат значение позиционного аргумента (square) и формирующей вывод в зависимости от аргумента опционального (-v):
Остановимся на действиях (actions). Они могут быть следующими:
— store: возвращает в пространство имен значение (после необязательного приведения типа). Как уже говорилось, store — действие по умолчанию;
— store_const: в основном используется для флагов. Либо вернет Вам значение, указанное в const, либо (если ничего не указано), None. Пример:
— store_true / store_false: аналог store_const, но для булевых True и False;
— append: возвращает список путем добавления в него значений агрументов. Пример:
— append_const: возвращение значения, определенного в спецификации аргумента, в список. Пока у меня не было кейса, в котором понадобился бы append_const.
— count: как следует из названия, считает, сколько раз встречается значение данного аргумента. Пример:
В зависимости от переданного в конструктор парсера аргумента add_help (булевого типа), будет определяться, включать или не включать в стандартный вывод по ключам ['-h', '--help'] сообщения о помощи. То же самое будет иместь место с аргументом version (строкового типа), ключи по умолчанию: ['-v', '--version']. При запросе помощи или номера версии, дальнейшее выполнение прерывается.
Иногда необходимо определить некий набор параметров командной строки, который будет распространяться на все парсеры Вашей программы. В данном случае часто приводят пример необходимости авторизации:
Обратите внимание, что родительский парсер создается с параметром add_help=False. Это сделано потому, что каждый парсер будет честно стараться добавить свой обработчик ключа '-h', чем вызовет конфликтную ситуацию. Отсюда возникает вопрос, что делать, если у вашего дочернего парсера имеются те же ключи, что и у родительского и при этом вы хотите их использовать без всяких конфликтов? Делается это простым добавлением аргумента conflict_handler:
Помимо вышеописанного подхода к обработке команд разного уровня, существует еще и альтернативный подход, позволяющий объединить обработку всех команд в одной программе, используя субпарсеры (subparsers). Лучше всего сам за себя расскажет пример:
Вот что выдаст программа с ключом '-h':
В примере можно отметить следующие вещи:
1. позиционные аргументы list, create, передаваемые программе — по сути субпарсеры;
2. аргумент '--read-only' субпарсера create_parser — опциональный, dir_name — необходимый для обоих субпарсеров;
3. предусмотрена справка (помощь) как для парсера, так и для каждго из субпарсеров.
Вообще, argparse — довольно мощная и легкая библиотека, предоставляющая, на мой взгляд, очень удобный интерфейс для работы с параметрами командной строки. В следующий раз постараюсь охватить такие вопросы, как файловые аргументы (для более продвинутой работы с файлами), переменные списки аргументов, группы аргументов и более подробно остановиться на типизации аргументов.
Спасибо за внимание.
Список литературы:
Why aren't getopt and optparse enough (PEP 389)
Argparse positional and optional arguments
Argparse documentation
Parser for command-line options, arguments and sub-commands
Для начала рассмотрим, что интересного предлагает argparse.
Argparse — это изящный инструмент для:
- анализа аргументов sys.argv;
- конвертирования строковых аргументов в объекты Вашей программы и работа с ними;
- форматирования и вывода информативных подсказок;
- многого другого.
Одним из аргументов противников включения argparse в Python был довод о том, что в стандартных модулях и без этого содержится две библиотеки для семантической обработки (парсинга) параметров командной строки. Однако, как заявляют разработчики argparse, библиотеки getopt и optparse уступают argparse по нескольким причинам:
- обладая всей полнотой действий с обычными параметрами командной строки, они не умеют обрабатывать позиционные аргументы (positional arguments). Позиционные аргументы — это аргументы, влияющие на работу программы, в зависимости от порядка, в котором они в эту программу передаются. Простейший пример — программа cp, имеющая минимум 2 таких аргумента («cp source destination»).
- argparse дает на выходе более качественные сообщения о подсказке при минимуме затрат (в этом плане при работе с optparse часто можно наблюдать некоторую избыточность кода);
- argparse дает возможность программисту устанавливать для себя, какие символы являются параметрами, а какие нет. В отличие от него, optparse считает опции с синтаксисом наподобии "-pf, -file, +rgb, /f и т.п. «внутренне противоречивыми» и «не поддерживается optpars'ом и никогда не будет»;
- argparse даст Вам возможность использовать несколько значений переменных у одного аргумента командной строки (nargs);
- argparse поддерживает субкоманды (subcommands). Это когда основной парсер отсылает к другому (субпарсеру), в зависимости от аргументов на входе.
Для начала работы с argparse необходимо задать парсер:
ap.py:
import argparse
parser = argparse.ArgumentParser(description='Great Description To Be Here')
Далее, парсеру стоит указать, какие объекты Вы от него ждете. В частном случае, это может выглядеть так:
parser.add_argument('-n', action='store', dest='n', help='Simple value')
Если действие (action) для данного аргумента не задано, то по умолчанию он будет сохраняться (store) в namespace, причем мы также можем указать тип этого аргумента (int, boolean и тд). Если имя возвращаемого аргумента (dest) задано, его значение будет сохранено в соответствующем атрибуте namespace.
В нашем случае:
print parser.parse_args(['-n', '3'])
Namespace(n='3')
print parser.parse_args([])
Namespace(n=None)
print parser.parse_args(['-a', '3'])
error: unrecognized arguments: -a 3
Простой пример программы, возводящей в квадрат значение позиционного аргумента (square) и формирующей вывод в зависимости от аргумента опционального (-v):
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
help="display a square of a given number")
parser.add_argument("-v", "--verbose", action="store_true",
help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbose:
print("the square of {} equals {}".format(args.square, answer))
else:
print(answer)
Остановимся на действиях (actions). Они могут быть следующими:
— store: возвращает в пространство имен значение (после необязательного приведения типа). Как уже говорилось, store — действие по умолчанию;
— store_const: в основном используется для флагов. Либо вернет Вам значение, указанное в const, либо (если ничего не указано), None. Пример:
parser.add_argument('--LifetheUniverseandEverything', action='store_const', const=42)
print parser.parse_args(['--LifetheUniverseandEverything'])
Namespace(LifetheUniverseandEverything=42)
— store_true / store_false: аналог store_const, но для булевых True и False;
— append: возвращает список путем добавления в него значений агрументов. Пример:
parser.add_argument('--l', action='append')
print parser.parse_args('--l a --l b --l Y'.split())
Namespace(l=['abY'])
— append_const: возвращение значения, определенного в спецификации аргумента, в список. Пока у меня не было кейса, в котором понадобился бы append_const.
— count: как следует из названия, считает, сколько раз встречается значение данного аргумента. Пример:
parser.add_argument('--verbose', '-v', action='count')
print parser.parse_args('-vvv'.split())
Namespace(verbose=3)
В зависимости от переданного в конструктор парсера аргумента add_help (булевого типа), будет определяться, включать или не включать в стандартный вывод по ключам ['-h', '--help'] сообщения о помощи. То же самое будет иместь место с аргументом version (строкового типа), ключи по умолчанию: ['-v', '--version']. При запросе помощи или номера версии, дальнейшее выполнение прерывается.
parser = argparse.ArgumentParser(add_help=True, version='4.0')
Иногда необходимо определить некий набор параметров командной строки, который будет распространяться на все парсеры Вашей программы. В данном случае часто приводят пример необходимости авторизации:
parent_parser = argparse.ArgumentParser(add_help=False)
parent_parser.add_argument('--user', action="store")
parent_parser.add_argument('--password', action="store")
child_parser = argparse.ArgumentParser(parents=[parent_parser])
child_parser.add_argument('--show_all', action="store_true")
print child_parser.parse_args(['--user', 'guest'])
Namespace(password=None, show_all=False, user='guest')
Обратите внимание, что родительский парсер создается с параметром add_help=False. Это сделано потому, что каждый парсер будет честно стараться добавить свой обработчик ключа '-h', чем вызовет конфликтную ситуацию. Отсюда возникает вопрос, что делать, если у вашего дочернего парсера имеются те же ключи, что и у родительского и при этом вы хотите их использовать без всяких конфликтов? Делается это простым добавлением аргумента conflict_handler:
parent_parser = argparse.ArgumentParser(add_help=False)
parent_parser.add_argument('--user', action="store")
parent_parser.add_argument('--password', action="store")
child_parser = argparse.ArgumentParser(parents=[parent_parser], conflict_handler='resolve')
child_parser.add_argument('--user', action="store", default="Guest")
print child_parser.parse_args()
Namespace(password=None, user='Guest')
Помимо вышеописанного подхода к обработке команд разного уровня, существует еще и альтернативный подход, позволяющий объединить обработку всех команд в одной программе, используя субпарсеры (subparsers). Лучше всего сам за себя расскажет пример:
ap.py
import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(help='List of commands')
# A list command
list_parser = subparsers.add_parser('list', help='List contents')
list_parser.add_argument('dirname', action='store', help='Directory to list')
# A create command
create_parser = subparsers.add_parser('create', help='Create a directory')
create_parser.add_argument('dirname', action='store', help='New directory to create')
create_parser.add_argument('--read-only', default=False, action='store_true',
help='Set permissions to prevent writing to the directory',
)
Вот что выдаст программа с ключом '-h':
usage: ap.py [-h] {list,create} ...
positional arguments:
{list,create} list of commands
list List contents
create Create a directory
optional arguments:
-h, --help show this help message and exit
В примере можно отметить следующие вещи:
1. позиционные аргументы list, create, передаваемые программе — по сути субпарсеры;
2. аргумент '--read-only' субпарсера create_parser — опциональный, dir_name — необходимый для обоих субпарсеров;
3. предусмотрена справка (помощь) как для парсера, так и для каждго из субпарсеров.
Вообще, argparse — довольно мощная и легкая библиотека, предоставляющая, на мой взгляд, очень удобный интерфейс для работы с параметрами командной строки. В следующий раз постараюсь охватить такие вопросы, как файловые аргументы (для более продвинутой работы с файлами), переменные списки аргументов, группы аргументов и более подробно остановиться на типизации аргументов.
Спасибо за внимание.
Список литературы:
Why aren't getopt and optparse enough (PEP 389)
Argparse positional and optional arguments
Argparse documentation
Parser for command-line options, arguments and sub-commands