optparse — Парсер для опций командной строки¶
Исходный код: Lib/optparse.py.
Не рекомендуется, начиная с версии 3.2: Модуль optparse является устаревшим и не будет развиваться дальше; развитие будет продолжено с модулем argparse.
optparse - это более удобная, гибкая и мощная библиотека для разбора опций командной строки, чем старый модуль getopt. optparse использует более декларативный стиль разбора командной строки: вы создаете экземпляр OptionParser, заполняете его опциями и разбираете командную строку. optparse позволяет пользователям указывать опции в обычном синтаксисе GNU/POSIX и дополнительно генерирует для вас сообщения об использовании и справку.
Вот пример использования optparse в простом сценарии:
from optparse import OptionParser
...
parser = OptionParser()
parser.add_option("-f", "--file", dest="filename",
help="write report to FILE", metavar="FILE")
parser.add_option("-q", "--quiet",
action="store_false", dest="verbose", default=True,
help="don't print status messages to stdout")
(options, args) = parser.parse_args()
С помощью этих нескольких строк кода пользователи вашего скрипта теперь могут делать «обычные вещи» в командной строке, например:
<yourscript> --file=outfile -q
По мере разбора командной строки optparse устанавливает атрибуты объекта options, возвращаемого parse_args(), на основе значений, введенных пользователем из командной строки. Когда parse_args() возвращается после разбора этой командной строки, options.filename будет "outfile", а options.verbose будет False. optparse поддерживает как длинные, так и короткие опции, позволяет объединять короткие опции вместе, а также позволяет связывать опции с их аргументами различными способами. Таким образом, все следующие командные строки эквивалентны приведенному выше примеру:
<yourscript> -f outfile --quiet
<yourscript> --quiet --file outfile
<yourscript> -q -foutfile
<yourscript> -qfoutfile
Кроме того, пользователи могут выполнить один из следующих пунктов:
<yourscript> -h
<yourscript> --help
и optparse выведут краткую информацию о параметрах вашего сценария:
Usage: <yourscript> [options]
Options:
-h, --help show this help message and exit
-f FILE, --file=FILE write report to FILE
-q, --quiet don't print status messages to stdout
где значение yourscript определяется во время выполнения (обычно из sys.argv[0]).
Справочная информация¶
optparse был явно разработан для поощрения создания программ с простыми, обычными интерфейсами командной строки. С этой целью он поддерживает только наиболее распространенный синтаксис и семантику командной строки, обычно используемые в Unix. Если вы не знакомы с этими соглашениями, прочитайте этот раздел, чтобы ознакомиться с ними.
Терминология¶
- аргумент
строка, введенная в командной строке и переданная оболочкой в
execl()илиexecv(). В Python аргументы - это элементыsys.argv[1:](sys.argv[0]- это имя выполняемой программы). В оболочках Unix также используется термин «слово».Иногда желательно подставить список аргументов, отличный от
sys.argv[1:], поэтому следует читать «аргумент» как «элементsys.argv[1:]или другого списка, предоставляемого в качестве заменыsys.argv[1:]».- вариант
аргумент, используемый для предоставления дополнительной информации, чтобы направлять или настраивать выполнение программы. Существует множество различных синтаксисов для опций; традиционный синтаксис Unix - это дефис («-«), за которым следует одна буква, например,
-xили-F. Кроме того, традиционный синтаксис Unix позволяет объединять несколько опций в один аргумент, например,-x -Fэквивалентен-xF. Проект GNU ввел--, за которым следует серия слов, разделенных дефисом, например--fileили--dry-run. Это единственные два синтаксиса опций, предоставляемыхoptparse.Некоторые другие синтаксисы опций, которые видел мир, включают:
дефис, за которым следует несколько букв, например,
-pf(это не то же самое, что несколько вариантов, объединенных в один аргумент)дефис, за которым следует целое слово, например,
-file(технически это эквивалентно предыдущему синтаксису, но обычно они не встречаются в одной программе)знак плюс, за которым следует одна буква, или несколько букв, или слово, например,
+f,+rgbкосая черта, за которой следует буква, или несколько букв, или слово, например,
/f,/file
Эти синтаксисы опций не поддерживаются
optparseи никогда не будут поддерживаться. Это сделано намеренно: первые три нестандартны для любой среды, а последний имеет смысл только в том случае, если вы ориентируетесь исключительно на Windows или некоторые старые платформы (например, VMS, MS-DOS).- аргумент опции
аргумент, который следует за опцией, тесно связан с этой опцией и потребляется из списка аргументов, когда эта опция есть. С помощью
optparseаргументы опции могут находиться либо в отдельном аргументе от своей опции:-f foo --file foo
или включены в один аргумент:
-ffoo --file=foo
Обычно опция либо принимает аргумент, либо нет. Многие люди хотят иметь функцию «необязательных аргументов опции», то есть некоторые опции будут принимать аргумент, если видят его, и не будут, если не видят. Это несколько противоречиво, потому что делает разбор неоднозначным: если
-aпринимает необязательный аргумент, а-b- это совсем другая опция, как нам интерпретировать-ab? Из-за этой неоднозначностиoptparseне поддерживает эту возможность.- позиционный аргумент
что-то оставшееся в списке аргументов после разбора опций, то есть после того, как опции и их аргументы были разобраны и удалены из списка аргументов.
- необходимая опция
опция, которая должна быть задана в командной строке; обратите внимание, что фраза «требуемая опция» является самопротиворечивой в английском языке.
optparseне мешает вам реализовать требуемые опции, но и не сильно помогает вам в этом.
Например, рассмотрим эту гипотетическую командную строку:
prog -v --report report.txt foo bar
-v и --report являются опциями. Если предположить, что --report принимает один аргумент, то report.txt является аргументом опции. foo и bar являются позиционными аргументами.
Для чего нужны опционы?¶
Опции используются для предоставления дополнительной информации, чтобы настроить или адаптировать выполнение программы. Если вы не поняли, опции обычно являются опциональными. Программа должна работать нормально без каких-либо опций. (Выберите произвольную программу из наборов инструментов Unix или GNU. Может ли она работать без каких-либо опций вообще и сохранять смысл? Основными исключениями являются find, tar и dd- все они являются мутантами, которые справедливо критиковались за их нестандартный синтаксис и запутанный интерфейс).
Многие люди хотят, чтобы в их программах были «обязательные опции». Подумайте об этом. Если это обязательно, то это не опционально! Если есть часть информации, которая абсолютно необходима вашей программе для успешного выполнения, то для этого и нужны позиционные аргументы.
В качестве примера хорошего дизайна интерфейса командной строки рассмотрим скромную утилиту cp для копирования файлов. Не имеет особого смысла пытаться копировать файлы, не указав место назначения и хотя бы один источник. Следовательно, cp не работает, если вы запустите ее без аргументов. Однако у нее есть гибкий и полезный синтаксис, который вообще не требует никаких опций:
cp SOURCE DEST
cp SOURCE ... DEST-DIR
Вы можете далеко зайти, используя только это. Большинство реализаций cp предоставляют множество опций для настройки того, как именно копируются файлы: вы можете сохранять режим и время модификации, избегать следования по симлинкам, спрашивать, прежде чем уничтожать существующие файлы, и т. д. Но все это не отвлекает от основной задачи cp, которая заключается в копировании либо одного файла в другой, либо нескольких файлов в другой каталог.
Для чего нужны позиционные аргументы?¶
Позиционные аргументы предназначены для тех частей информации, которые абсолютно, позитивно необходимы вашей программе для выполнения.
Хороший пользовательский интерфейс должен иметь как можно меньше абсолютных требований. Если для успешного запуска вашей программы требуется 17 отдельных частей информации, не имеет особого значения, каким образом* вы получите эту информацию от пользователя - большинство людей сдадутся и уйдут, прежде чем успешно запустят программу. Это относится к интерфейсу пользователя, будь то командная строка, конфигурационный файл или графический интерфейс: если вы предъявляете столько требований к пользователям, большинство из них просто сдадутся.
Короче говоря, постарайтесь свести к минимуму количество информации, которую пользователи должны предоставлять в обязательном порядке - используйте разумные значения по умолчанию, когда это возможно. Конечно, вы также хотите сделать свои программы достаточно гибкими. Для этого и существуют опции. Опять же, неважно, будут ли это записи в конфигурационном файле, виджеты в диалоге «Preferences» графического интерфейса или опции командной строки - чем больше опций вы реализуете, тем более гибкой будет ваша программа, и тем сложнее станет ее реализация. Слишком большая гибкость, конечно, имеет и недостатки; слишком большое количество опций может перегрузить пользователей и сделать ваш код гораздо более сложным для сопровождения.
Учебник¶
Хотя optparse является довольно гибким и мощным, в большинстве случаев он также прост в использовании. В этом разделе рассматриваются шаблоны кода, которые являются общими для любой программы, основанной на optparse.
Сначала нужно импортировать класс OptionParser; затем в начале основной программы создать экземпляр OptionParser:
from optparse import OptionParser
...
parser = OptionParser()
Затем можно приступить к определению опций. Основной синтаксис следующий:
parser.add_option(opt_str, ...,
attr=value, ...)
Каждая опция имеет одну или несколько строк опций, например -f или --file, и несколько атрибутов опций, которые говорят optparse, что ожидать и что делать, когда он встречает эту опцию в командной строке.
Как правило, каждая опция имеет одну короткую строку опции и одну длинную строку опции, например:
parser.add_option("-f", "--file", ...)
Каждая опция имеет одну или несколько строк опций, например или , и несколько атрибутов опций, которые говорят , что ожидать и что делать, когда он встречает эту опцию в командной строке.
Строки опций, переданные в OptionParser.add_option(), фактически являются метками для опции, определенной этим вызовом. Для краткости мы будем часто ссылаться на встречу опции в командной строке; в действительности optparse встречает строки опций и ищет опции из них.
Когда все опции определены, дайте команду optparse разобрать командную строку вашей программы:
(options, args) = parser.parse_args()
(Если хотите, вы можете передать пользовательский список аргументов в parse_args(), но это редко необходимо: по умолчанию он использует sys.argv[1:]).
parse_args() возвращает два значения:
options, объект, содержащий значения для всех ваших опций - например, если--fileпринимает единственный строковый аргумент, тоoptions.fileбудет именем файла, предоставленным пользователем, илиNone, если пользователь не предоставил эту опциюargs, список позиционных аргументов, оставшихся после разбора опций
В этом учебном разделе рассматриваются только четыре наиболее важных атрибута опций: action, type, dest (назначение) и help. Из них action является наиболее фундаментальным.
Понимание действий опционов¶
Действия указывают optparse, что делать, когда он встречает опцию в командной строке. Существует фиксированный набор действий, жестко закодированный в optparse; добавление новых действий - это продвинутая тема, рассматриваемая в разделе Расширение optparse. Большинство действий указывают optparse сохранить значение в некоторой переменной - например, взять строку из командной строки и сохранить ее в атрибуте options.
Если вы не указали действие опции, optparse по умолчанию принимает значение store.
Действие магазина¶
Наиболее распространенным действием опции является store, которое говорит optparse взять следующий аргумент (или остаток текущего аргумента), убедиться, что он правильного типа, и сохранить его в выбранном вами месте назначения.
Например:
parser.add_option("-f", "--file",
action="store", type="string", dest="filename")
Теперь давайте составим фальшивую командную строку и попросим optparse разобрать ее:
args = ["-f", "foo.txt"]
(options, args) = parser.parse_args(args)
Когда optparse видит строку опций -f, он потребляет следующий аргумент, foo.txt, и сохраняет его в options.filename. Таким образом, после этого вызова parse_args(), options.filename становится "foo.txt".
Некоторые другие типы опций, поддерживаемые optparse, это int и float. Вот опция, которая ожидает целочисленный аргумент:
parser.add_option("-n", type="int", dest="num")
Обратите внимание, что у этой опции нет длинной строки опции, что вполне допустимо. Также нет явного действия, поскольку по умолчанию стоит store.
Давайте разберем еще одну поддельную командную строку. На этот раз мы засунем аргумент опции прямо против опции: поскольку -n42 (один аргумент) эквивалентен -n 42 (два аргумента), код
(options, args) = parser.parse_args(["-n42"])
print(options.num)
выведет 42.
Если тип не указан, optparse предполагает string. В сочетании с тем, что действие по умолчанию store, это означает, что наш первый пример может быть намного короче:
parser.add_option("-f", "--file", dest="filename")
Если вы не указали место назначения, optparse вычисляет разумное значение по умолчанию из строк опций: если первая длинная строка опций --foo-bar, то местом назначения по умолчанию будет foo_bar. Если длинных строк опций нет, optparse рассматривает первую короткую строку опций: пункт назначения по умолчанию для -f - f.
optparse также включает встроенный тип complex. Добавление типов рассматривается в разделе Расширение optparse.
Обработка булевых (флаговых) опций¶
Опции флагов - установка переменной в true или false при появлении определенной опции - довольно распространены. optparse поддерживает их с помощью двух отдельных действий, store_true и store_false. Например, у вас может быть флаг verbose, который включается с помощью -v и выключается с помощью -q:
parser.add_option("-v", action="store_true", dest="verbose")
parser.add_option("-q", action="store_false", dest="verbose")
Здесь у нас есть два разных варианта с одинаковым назначением, что совершенно нормально. (Это просто означает, что вы должны быть немного осторожны при установке значений по умолчанию - см. ниже).
Когда optparse встречает -v в командной строке, он устанавливает options.verbose в True; когда он встречает -q, options.verbose устанавливается в False.
Другие действия¶
Некоторые другие действия, поддерживаемые optparse, следующие:
"store_const"хранить постоянное значение
"append"добавить аргумент этой опции в список
"count"увеличить счетчик на единицу
"callback"вызов указанной функции
Они рассматриваются в разделе Справочное руководство и в разделе Обратные вызовы опций.
Значения по умолчанию¶
Все приведенные выше примеры подразумевают установку некоторой переменной («назначения») при появлении определенных опций командной строки. Что произойдет, если эти опции никогда не появятся? Поскольку мы не задали никаких значений по умолчанию, все они будут установлены в None. Обычно это нормально, но иногда хочется большего контроля. optparse позволяет задать значение по умолчанию для каждого пункта назначения, которое присваивается до разбора командной строки.
Сначала рассмотрим пример verbose/quiet. Если мы хотим, чтобы optparse устанавливал verbose в True, пока не появится -q, то мы можем сделать следующее:
parser.add_option("-v", action="store_true", dest="verbose", default=True)
parser.add_option("-q", action="store_false", dest="verbose")
Поскольку значения по умолчанию применяются к назначению, а не к какой-либо конкретной опции, а эти две опции имеют одинаковое назначение, это абсолютно эквивалентно:
parser.add_option("-v", action="store_true", dest="verbose")
parser.add_option("-q", action="store_false", dest="verbose", default=True)
Подумайте вот о чем:
parser.add_option("-v", action="store_true", dest="verbose", default=False)
parser.add_option("-q", action="store_false", dest="verbose", default=True)
Опять же, значение по умолчанию для verbose будет True: последнее значение по умолчанию, предоставленное для любого конкретного назначения, является тем, которое имеет значение.
Более понятным способом задания значений по умолчанию является метод set_defaults() OptionParser, который вы можете вызвать в любое время перед вызовом parse_args():
parser.set_defaults(verbose=True)
parser.add_option(...)
(options, args) = parser.parse_args()
Как и раньше, последнее значение, указанное для данного пункта назначения опции, является значением по умолчанию. Для ясности старайтесь использовать один или другой метод установки значений по умолчанию, а не оба.
Генерация помощи¶
Способность optparse автоматически генерировать справку и текст использования полезна для создания дружественных интерфейсов командной строки. Все, что вам нужно сделать, это указать значение help для каждой опции и, по желанию, краткое сообщение об использовании всей вашей программы. Вот OptionParser, заполненный удобными для пользователя (документированными) опциями:
usage = "usage: %prog [options] arg1 arg2"
parser = OptionParser(usage=usage)
parser.add_option("-v", "--verbose",
action="store_true", dest="verbose", default=True,
help="make lots of noise [default]")
parser.add_option("-q", "--quiet",
action="store_false", dest="verbose",
help="be vewwy quiet (I'm hunting wabbits)")
parser.add_option("-f", "--filename",
metavar="FILE", help="write output to FILE")
parser.add_option("-m", "--mode",
default="intermediate",
help="interaction mode: novice, intermediate, "
"or expert [default: %default]")
Если optparse встречает -h или --help в командной строке, или если вы просто вызываете parser.print_help(), он печатает следующее на стандартный вывод:
Usage: <yourscript> [options] arg1 arg2
Options:
-h, --help show this help message and exit
-v, --verbose make lots of noise [default]
-q, --quiet be vewwy quiet (I'm hunting wabbits)
-f FILE, --filename=FILE
write output to FILE
-m MODE, --mode=MODE interaction mode: novice, intermediate, or
expert [default: intermediate]
(Если вывод справки вызван опцией help, optparse завершается после печати текста справки).
Здесь многое делается для того, чтобы помочь optparse сформировать наилучшее возможное сообщение о помощи:
сценарий определяет свое собственное сообщение об использовании:
usage = "usage: %prog [options] arg1 arg2"
optparseрасширяет%progв строке использования до имени текущей программы, т.е.os.path.basename(sys.argv[0]). Расширенная строка выводится перед подробной справкой по опциям.Если вы не предоставите строку использования,
optparseбудет использован простой, но разумный вариант по умолчанию:"Usage: %prog [options]", что хорошо, если ваш скрипт не принимает никаких позиционных аргументов.Каждая опция определяет строку справки и не заботится об обертывании строк -
optparseпозаботится об обертывании строк и приведении справки в надлежащий вид.Опции, принимающие значение, указывают на этот факт в автоматически создаваемом справочном сообщении, например, для опции «mode»:
-m MODE, --mode=MODE
Здесь «MODE» называется мета-переменной: она обозначает аргумент, который пользователь должен передать в
-m/--mode. По умолчаниюoptparseпреобразует имя целевой переменной в верхний регистр и использует его для мета-переменной. Иногда это не то, что вам нужно - например, опция--filenameявно устанавливаетmetavar="FILE", в результате чего автоматически создается следующее описание опции:-f FILE, --filename=FILE
Однако это важно не только для экономии места: в написанном вручную тексте справки мета-переменная
FILEиспользуется для подсказки пользователю, что существует связь между полуформальным синтаксисом-f FILEи неформальным семантическим описанием «записать вывод в FILE». Это простой, но эффективный способ сделать текст справки намного понятнее и полезнее для конечных пользователей.опции, имеющие значение по умолчанию, могут включать
%defaultв строку справки—optparseзаменит его наstr()значение по умолчанию опции. Если опция не имеет значения по умолчанию (или значение по умолчанию равноNone),%defaultрасширяется доnone.
Параметры группировки¶
При работе с большим количеством опций удобно группировать эти опции для лучшего вывода справки. Параметр OptionParser может содержать несколько групп опций, каждая из которых может содержать несколько опций.
Группа опций получается с помощью класса OptionGroup:
-
class
optparse.OptionGroup(parser, title, description=None)¶ где
парсер является экземпляром
OptionParser, в который будет вставлена группа, чтобыtitle - название группы
описание, необязательное, представляет собой длинное описание группы
OptionGroup наследуется от OptionContainer (как и OptionParser) и поэтому метод add_option() может быть использован для добавления опции в группу.
После объявления всех опций с помощью метода OptionParser add_option_group() группа добавляется к ранее определенному парсеру.
Продолжая использовать синтаксический анализатор, определенный в предыдущем разделе, добавить OptionGroup к синтаксическому анализатору очень просто:
group = OptionGroup(parser, "Dangerous Options",
"Caution: use these options at your own risk. "
"It is believed that some of them bite.")
group.add_option("-g", action="store_true", help="Group option.")
parser.add_option_group(group)
Это приведет к следующему выводу справки:
Usage: <yourscript> [options] arg1 arg2
Options:
-h, --help show this help message and exit
-v, --verbose make lots of noise [default]
-q, --quiet be vewwy quiet (I'm hunting wabbits)
-f FILE, --filename=FILE
write output to FILE
-m MODE, --mode=MODE interaction mode: novice, intermediate, or
expert [default: intermediate]
Dangerous Options:
Caution: use these options at your own risk. It is believed that some
of them bite.
-g Group option.
Более полный пример может включать использование более чем одной группы: продолжая предыдущий пример:
group = OptionGroup(parser, "Dangerous Options",
"Caution: use these options at your own risk. "
"It is believed that some of them bite.")
group.add_option("-g", action="store_true", help="Group option.")
parser.add_option_group(group)
group = OptionGroup(parser, "Debug Options")
group.add_option("-d", "--debug", action="store_true",
help="Print debug information")
group.add_option("-s", "--sql", action="store_true",
help="Print all SQL statements executed")
group.add_option("-e", action="store_true", help="Print every action done")
parser.add_option_group(group)
что приводит к следующему результату:
Usage: <yourscript> [options] arg1 arg2
Options:
-h, --help show this help message and exit
-v, --verbose make lots of noise [default]
-q, --quiet be vewwy quiet (I'm hunting wabbits)
-f FILE, --filename=FILE
write output to FILE
-m MODE, --mode=MODE interaction mode: novice, intermediate, or expert
[default: intermediate]
Dangerous Options:
Caution: use these options at your own risk. It is believed that some
of them bite.
-g Group option.
Debug Options:
-d, --debug Print debug information
-s, --sql Print all SQL statements executed
-e Print every action done
Еще один интересный метод, в частности, при программной работе с группами опций:
-
OptionParser.get_option_group(opt_str)¶ Возвращает
OptionGroup, к которому принадлежит короткая или длинная строка опции opt_str (например,'-o'или'--option'). Если такойOptionGroupне существует, возвращаетсяNone.
Печать строки версии¶
Подобно строке краткого использования, optparse может также вывести строку версии вашей программы. Вы должны предоставить эту строку в качестве аргумента version в OptionParser:
parser = OptionParser(usage="%prog [-f] [-q]", version="%prog 1.0")
%prog расширяется так же, как и в usage. Кроме этого, version может содержать все, что угодно. Когда вы предоставляете его, optparse автоматически добавляет опцию --version к вашему синтаксическому анализатору. Если он встречает эту опцию в командной строке, он расширяет вашу строку version (заменяя %prog), печатает ее в stdout и завершает работу.
Например, если ваш сценарий называется /usr/bin/foo:
$ /usr/bin/foo --version
foo 1.0
Следующие два метода можно использовать для печати и получения строки version:
-
OptionParser.print_version(file=None)¶ Выведите сообщение о версии текущей программы (
self.version) в file (по умолчанию stdout). Как и в случае сprint_usage(), любое вхождение%progвself.versionзаменяется именем текущей программы. Ничего не делает, еслиself.versionпуст или не определен.
-
OptionParser.get_version()¶ То же, что и
print_version(), но вместо печати возвращает строку версии.
Как optparse обрабатывает ошибки¶
Существует два широких класса ошибок, о которых приходится беспокоиться optparse: ошибки программистов и ошибки пользователей. Ошибки программиста - это, как правило, ошибочные вызовы OptionParser.add_option(), например, недопустимые строки опций, неизвестные атрибуты опций, отсутствующие атрибуты опций и т.д. С ними борются обычным способом: вызывают исключение (либо optparse.OptionError, либо TypeError) и дают программе завершиться.
Работа с ошибками пользователя гораздо важнее, поскольку они гарантированно случаются независимо от того, насколько стабилен ваш код. optparse может автоматически обнаружить некоторые ошибки пользователя, такие как плохие аргументы опций (передача -n 4x там, где -n принимает целочисленный аргумент), пропущенные аргументы (-n в конце командной строки, где -n принимает аргумент любого типа). Кроме того, вы можете вызвать OptionParser.error() для сигнализации определенного приложением состояния ошибки:
(options, args) = parser.parse_args()
...
if options.a and options.b:
parser.error("options -a and -b are mutually exclusive")
В любом случае, optparse обрабатывает ошибку одинаково: печатает сообщение об использовании программы и сообщение об ошибке в стандартную ошибку и завершает работу со статусом ошибки 2.
Рассмотрим первый пример, где пользователь передает 4x в опцию, которая принимает целое число:
$ /usr/bin/foo -n 4x
Usage: foo [options]
foo: error: option -n: invalid integer value: '4x'
Или, когда пользователь вообще не передает значение:
$ /usr/bin/foo -n
Usage: foo [options]
foo: error: -n option requires an argument
В генерируемых optparse- сообщениях об ошибках обязательно указывается опция, вызвавшая ошибку; не забудьте сделать то же самое при вызове OptionParser.error() из кода вашего приложения.
Если поведение обработки ошибок по умолчанию в optparse не удовлетворяет вашим потребностям, вам нужно подкласс OptionParser и переопределить его методы exit() и/или error().
Собираем все вместе¶
Вот как обычно выглядят сценарии, основанные на optparse::
from optparse import OptionParser
...
def main():
usage = "usage: %prog [options] arg"
parser = OptionParser(usage)
parser.add_option("-f", "--file", dest="filename",
help="read data from FILENAME")
parser.add_option("-v", "--verbose",
action="store_true", dest="verbose")
parser.add_option("-q", "--quiet",
action="store_false", dest="verbose")
...
(options, args) = parser.parse_args()
if len(args) != 1:
parser.error("incorrect number of arguments")
if options.verbose:
print("reading %s..." % options.filename)
...
if __name__ == "__main__":
main()
Справочное руководство¶
Создание синтаксического анализатора¶
Первым шагом в использовании optparse является создание экземпляра OptionParser.
-
class
optparse.OptionParser(...)¶ Конструктор OptionParser не имеет обязательных аргументов, но имеет ряд необязательных аргументов в виде ключевых слов. Вы всегда должны передавать их как аргументы ключевых слов, т.е. не полагаться на порядок объявления аргументов.
usage(по умолчанию:"%prog [options]")Краткое описание использования, которое следует печатать, когда ваша программа выполняется неправильно или с опцией помощи. Когда
optparseпечатает строку использования, он расширяет%progдоos.path.basename(sys.argv[0])(или доprog, если вы передали этот аргумент ключевого слова). Чтобы подавить сообщение об использовании, передайте специальное значениеoptparse.SUPPRESS_USAGE.option_list(по умолчанию:[])Список объектов Option для заполнения парсера. Опции в
option_listдобавляются после любых опций вstandard_option_list(атрибут класса, который может быть установлен подклассами OptionParser), но перед любыми опциями версии или справки. Устарело; вместо этого используйтеadd_option()после создания парсера.option_class(по умолчанию: optparse.Option)Класс для использования при добавлении опций к синтаксическому анализатору в
add_option().version(по умолчанию:None)Строка версии для печати, когда пользователь предоставляет опцию версии. Если для
versionзадано значение true,optparseавтоматически добавляет опцию версии с единственной строкой опции--version. Подстрока%progрасширяется так же, как и дляusage.conflict_handler(по умолчанию:"error")Определяет, что делать, когда в синтаксический анализатор добавляются опции с конфликтующими строками опций; см. раздел Противоречия между вариантами.
description(по умолчанию:None)Абзац текста, дающий краткий обзор вашей программы.
optparseпереформатирует этот абзац под текущую ширину терминала и печатает его, когда пользователь запрашивает помощь (послеusage, но перед списком опций).formatter(по умолчанию: новыйIndentedHelpFormatter)Экземпляр optparse.HelpFormatter, который будет использоваться для печати текста справки.
optparseпредоставляет два конкретных класса для этой цели: IndentedHelpFormatter и TitledHelpFormatter.add_help_option(по умолчанию:True)Если true,
optparseдобавит опцию помощи (со строками опций-hи--help) к парсеру.progСтрока, которую следует использовать при расширении
%progвusageиversionвместоos.path.basename(sys.argv[0]).epilog(по умолчанию:None)Параграф текста справки, который будет напечатан после справки по опциям.
Наполнение синтаксического анализатора¶
Существует несколько способов заполнения синтаксического анализатора опциями. Предпочтительным является использование OptionParser.add_option(), как показано в разделе Учебник. add_option() может быть вызван одним из двух способов:
передать ему экземпляр Option (как возвращено командой
make_option())передайте ему любую комбинацию позиционных и ключевых аргументов, которые приемлемы для
make_option()(т.е. для конструктора Option), и он создаст для вас экземпляр Option
Другая альтернатива - передать конструктору OptionParser список предварительно сконструированных экземпляров Option, как в:
option_list = [
make_option("-f", "--filename",
action="store", type="string", dest="filename"),
make_option("-q", "--quiet",
action="store_false", dest="verbose"),
]
parser = OptionParser(option_list=option_list)
(make_option() - это фабричная функция для создания экземпляров Option; в настоящее время это псевдоним конструктора Option. Будущая версия optparse может разделить Option на несколько классов, и make_option() будет выбирать нужный класс для инстанцирования. Не инстанцируйте Option напрямую).
Определение опций¶
Каждый экземпляр Option представляет собой набор синонимичных строк опций командной строки, например, -f и --file. Вы можете указать любое количество коротких или длинных строк опций, но вы должны указать хотя бы одну общую строку опций.
Каноническим способом создания экземпляра Option является метод add_option() в OptionParser.
-
OptionParser.add_option(option)¶ -
OptionParser.add_option(*opt_str, attr=value, ...) Чтобы определить опцию с помощью только короткой строки опции:
parser.add_option("-f", attr=value, ...)
А для определения опции достаточно длинной строки опции:
parser.add_option("--foo", attr=value, ...)
Аргументы ключевых слов определяют атрибуты нового объекта Option. Наиболее важным атрибутом опции является
action, и он в значительной степени определяет, какие другие атрибуты являются релевантными или необходимыми. Если вы передадите неактуальные атрибуты опции или не передадите необходимые,optparseвызовет исключениеOptionError, объясняющее вашу ошибку.Действие* опции определяет, что делает
optparse, когда встречает эту опцию в командной строке. Стандартные действия опции, жестко закодированные вoptparse, следующие:"store"хранить аргумент этой опции (по умолчанию)
"store_const"хранить постоянное значение
"store_true"хранить
True"store_false"хранить
False"append"добавить аргумент этой опции в список
"append_const"добавление постоянного значения в список
"count"увеличить счетчик на единицу
"callback"вызов указанной функции
"help"вывести сообщение об использовании, включая все опции и документацию по ним
(Если вы не указали действие, по умолчанию используется
"store". Для этого действия вы также можете указать атрибуты опцийtypeиdest; см. раздел Стандартные действия опций).
Как видите, большинство действий связано с сохранением или обновлением какого-либо значения. optparse всегда создает для этого специальный объект, условно называемый options (он бывает экземпляром optparse.Values). Аргументы опций (и различные другие значения) хранятся как атрибуты этого объекта, в соответствии с атрибутом опции dest (назначения).
Например, когда вы вызываете
parser.parse_args()
одним из первых действий optparse является создание объекта options:
options = Values()
Если одна из опций в этом синтаксическом анализаторе определена через
parser.add_option("-f", "--file", action="store", type="string", dest="filename")
и разбираемая командная строка включает любое из следующих:
-ffoo
-f foo
--file=foo
--file foo
то optparse, увидев эту опцию, сделает эквивалент
options.filename = "foo"
Атрибуты опций type и dest почти так же важны, как action, но action - единственный, который имеет смысл для всех опций.
Атрибуты опций¶
Следующие атрибуты опции могут быть переданы в качестве аргументов ключевого слова в OptionParser.add_option(). Если вы передаете атрибут опции, который не относится к конкретной опции, или не передаете требуемый атрибут опции, optparse выдает сообщение OptionError.
-
Option.action¶ (по умолчанию:
"store")Определяет поведение
optparse, когда эта опция встречается в командной строке; доступные опции документированы here.
-
Option.type¶ (по умолчанию:
"string")Тип аргумента, ожидаемый этой опцией (например,
"string"или"int"); доступные типы опций документированы here.
-
Option.dest¶ (по умолчанию: извлекается из строк опций)
Если действие опции подразумевает запись или изменение значения где-либо, это указывает
optparse, куда его записать:destназывает атрибут объектаoptions, которыйoptparseстроит при разборе командной строки.
-
Option.default¶ Значение, используемое для назначения этой опции, если опция не видна в командной строке. См. также
OptionParser.set_defaults().
-
Option.nargs¶ (по умолчанию: 1)
Сколько аргументов типа
typeдолжно быть израсходовано при появлении этой опции. Если > 1,optparseбудет сохранять кортеж значений вdest.
-
Option.const¶ Для действий, которые хранят постоянное значение, постоянное значение для хранения.
-
Option.choices¶ Для опций типа
"choice"- список строк, из которых пользователь может выбирать.
-
Option.callback¶ Для опций с действием
"callback"- вызываемая переменная, которую следует вызывать при появлении этой опции. Подробную информацию об аргументах, передаваемых вызываемой программе, смотрите в разделе Обратные вызовы опций.
-
Option.callback_args¶ -
Option.callback_kwargs¶ Дополнительные позиционные и ключевые аргументы для передачи в
callbackпосле четырех стандартных аргументов обратного вызова.
-
Option.help¶ Текст справки, печатаемый для этой опции при выводе списка всех доступных опций после того, как пользователь ввел опцию
help(например,--help). Если текст справки не предоставлен, опция будет выведена без текста справки. Чтобы скрыть эту опцию, используйте специальное значениеoptparse.SUPPRESS_HELP.
Стандартные действия опций¶
Различные действия с опциями имеют несколько разные требования и эффекты. Большинство действий имеют несколько соответствующих атрибутов опции, которые вы можете указать, чтобы направить поведение optparse; некоторые имеют обязательные атрибуты, которые вы должны указать для любой опции, использующей это действие.
"store"[актуально:type,dest,nargs,choices].За опцией должен следовать аргумент, который преобразуется в значение в соответствии с
typeи сохраняется вdest. Еслиnargs> 1, из командной строки будет потребляться несколько аргументов; все они будут преобразованы в соответствии сtypeи сохранены вdestв виде кортежа. См. раздел Стандартные типы опций.Если указано
choices(список или кортеж строк), то тип по умолчанию будет"choice".Если
typeне указано, то по умолчанию используется"string".Если
destне задано,optparseопределяет место назначения из первой длинной строки опций (например,--foo-barподразумеваетfoo_bar). Если длинных строк опций нет,optparseопределяет место назначения из первой короткой строки опций (например,-fподразумеваетf).Пример:
parser.add_option("-f") parser.add_option("-p", type="float", nargs=3, dest="point")
При разборе командной строки
-f foo.txt -p 1 -3.5 4 -fbar.txt
optparseустановитoptions.f = "foo.txt" options.point = (1.0, -3.5, 4.0) options.f = "bar.txt"
"store_const"[required:const; relevant:dest]Значение
constсохраняется вdest.Пример:
parser.add_option("-q", "--quiet", action="store_const", const=0, dest="verbose") parser.add_option("-v", "--verbose", action="store_const", const=1, dest="verbose") parser.add_option("--noisy", action="store_const", const=2, dest="verbose")
Если видно
--noisy, тоoptparseустановитoptions.verbose = 2
"store_true"[релевантно:dest]Частный случай
"store_const", который сохраняетTrueдоdest."store_false"[релевантно:dest]Как
"store_true", но хранитFalse.Пример:
parser.add_option("--clobber", action="store_true", dest="clobber") parser.add_option("--no-clobber", action="store_false", dest="clobber")
"append"[актуально:type,dest,nargs,choices].За опцией должен следовать аргумент, который добавляется к списку в
dest. Если значение по умолчанию дляdestне задано, пустой список создается автоматически, когдаoptparseвпервые встречает эту опцию в командной строке. Еслиnargs> 1, используется несколько аргументов, и кортеж длиныnargsдобавляется кdest.Значения по умолчанию для
typeиdestтакие же, как и для действия"store".Пример:
parser.add_option("-t", "--tracks", action="append", type="int")
Если в командной строке встречается
-t3, тоoptparseделает эквивалент:options.tracks = [] options.tracks.append(int("3"))
Если чуть позже появится
--tracks=4, это означает:options.tracks.append(int("4"))
Действие
appendвызывает методappendна текущем значении опции. Это означает, что любое указанное значение по умолчанию должно иметь методappend. Это также означает, что если значение по умолчанию непустое, то элементы по умолчанию будут присутствовать в разобранном значении опции, а любые значения из командной строки будут добавлены после этих значений по умолчанию:>>> parser.add_option("--files", action="append", default=['~/.mypkg/defaults']) >>> opts, args = parser.parse_args(['--files', 'overrides.mypkg']) >>> opts.files ['~/.mypkg/defaults', 'overrides.mypkg']
"append_const"[required:const; relevant:dest]Как
"store_const", но значениеconstдобавляется кdest; как и в случае"append",destпо умолчанию равноNone, а пустой список автоматически создается при первой встрече с опцией."count"[релевантно:dest]Инкрементировать целое число, хранящееся по адресу
dest. Если значение по умолчанию не указано,destустанавливается в ноль перед первым инкрементом.Пример:
parser.add_option("-v", action="count", dest="verbosity")
В первый раз, когда
-vвстречается в командной строке,optparseделает эквивалент:options.verbosity = 0 options.verbosity += 1
Каждое последующее появление
-vприводит кoptions.verbosity += 1
"callback"[требуется:callback; актуально:type,nargs,callback_args,callback_kwargs].Вызовите функцию, указанную
callback, которая вызывается какfunc(option, opt_str, value, parser, *args, **kwargs)
Более подробно см. раздел Обратные вызовы опций.
"help"Вызовите функцию, указанную
usage, которая вызывается какЕсли для опции не задана строка
help, она все равно будет указана в справочном сообщении. Чтобы полностью исключить опцию, используйте специальное значениеoptparse.SUPPRESS_HELP.optparseавтоматически добавляет опциюhelpко всем OptionParsers, поэтому обычно вам не нужно ее создавать.Пример:
from optparse import OptionParser, SUPPRESS_HELP # usually, a help option is added automatically, but that can # be suppressed using the add_help_option argument parser = OptionParser(add_help_option=False) parser.add_option("-h", "--help", action="help") parser.add_option("-v", action="store_true", dest="verbose", help="Be moderately verbose") parser.add_option("--file", dest="filename", help="Input file to read data from") parser.add_option("--secret", help=SUPPRESS_HELP)
Если
optparseвидит в командной строке-hили--help, он выводит в stdout что-то вроде следующего справочного сообщения (предполагая, чтоsys.argv[0]- это"foo.py"):Usage: foo.py [options] Options: -h, --help Show this help message and exit -v Be moderately verbose --file=FILENAME Input file to read data from
После печати справочного сообщения
optparseзавершает ваш процесс командойsys.exit(0)."version"Выводит номер версии, переданный OptionParser, на stdout и завершает работу. Номер версии фактически форматируется и выводится методом
print_version()OptionParser. Обычно имеет значение, только если аргументversionпередан в конструктор OptionParser. Как и в случае с опциямиhelp, вы редко будете создавать опцииversion, посколькуoptparseавтоматически добавляет их, когда это необходимо.
Стандартные типы опций¶
optparse имеет пять встроенных типов опций: "string", "int", "choice", "float" и "complex". Если вам необходимо добавить новые типы опций, см. раздел Расширение optparse.
Аргументы строковых опций никак не проверяются и не преобразуются: текст командной строки сохраняется в месте назначения (или передается в обратный вызов) как есть.
Целочисленные аргументы (тип "int") разбираются следующим образом:
если число начинается с
0x, оно разбирается как шестнадцатеричное числоесли число начинается с
0, оно разбирается как восьмеричное числоесли число начинается с
0b, оно разбирается как двоичное числов противном случае, число анализируется как десятичное число
Преобразование выполняется вызовом int() с соответствующим основанием (2, 8, 10 или 16). Если это не удается, то и optparse тоже, хотя с более полезным сообщением об ошибке.
Аргументы опций "float" и "complex" преобразуются непосредственно с помощью float() и complex(), с аналогичной обработкой ошибок.
Опции "choice" являются подтипом опций "string". Атрибут опции choices (последовательность строк) определяет набор допустимых аргументов опции. optparse.check_choice() сравнивает аргументы опций, предоставленные пользователем, с этим основным списком и выдает сообщение OptionValueError, если указана недопустимая строка.
Разбор аргументов¶
Весь смысл создания и наполнения OptionParser заключается в вызове его метода parse_args():
(options, args) = parser.parse_args(args=None, values=None)
где входными параметрами являются
argsсписок аргументов для обработки (по умолчанию:
sys.argv[1:])valuesобъект
optparse.Valuesдля хранения аргументов опции (по умолчанию: новый экземплярValues) – если вы передадите существующий объект, параметры опции по умолчанию не будут инициализированы на нем
а возвращаемыми значениями являются
optionsтот же объект, который был передан как
values, или экземпляр optparse.Values, созданныйoptparse.argsоставшиеся позиционные аргументы после обработки всех опций
Наиболее распространенным вариантом использования является предоставление ни одного из аргументов ключевого слова. Если вы передадите values, оно будет модифицировано многократными вызовами setattr() (примерно по одному на каждый аргумент опции, сохраненный в пункте назначения опции) и возвращено parse_args().
Если parse_args() встречает какие-либо ошибки в списке аргументов, он вызывает метод OptionParser error() с соответствующим сообщением об ошибке для конечного пользователя. В итоге ваш процесс завершается со статусом выхода 2 (традиционный статус выхода Unix для ошибок командной строки).
Запросы и манипуляции с анализатором опций¶
Поведение парсера опций по умолчанию можно немного изменить, а также можно пошарить в своем парсере опций и посмотреть, что там есть. OptionParser предоставляет несколько методов, чтобы помочь вам:
-
OptionParser.disable_interspersed_args()¶ Устанавливает остановку синтаксического разбора на первом неопционе. Например, если
-aи-b- простые опции, не принимающие аргументов, тоoptparseобычно принимает такой синтаксис:prog -a arg1 -b arg2
и рассматривает его как эквивалент
prog -a -b arg1 arg2
Чтобы отключить эту функцию, вызовите
disable_interspersed_args(). Это восстанавливает традиционный синтаксис Unix, где разбор опций останавливается на первом аргументе, не являющемся опцией.Используйте это, если у вас есть командный процессор, который запускает другую команду, имеющую собственные опции, и вы хотите убедиться, что эти опции не перепутаются. Например, у каждой команды может быть свой набор опций.
-
OptionParser.enable_interspersed_args()¶ Устанавливает, что синтаксический разбор не останавливается на первом неопциионе, позволяя перемежать переключатели с аргументами команды. Это поведение по умолчанию.
-
OptionParser.get_option(opt_str)¶ Устанавливает, что синтаксический разбор не останавливается на первом неопциионе, позволяя перемежать переключатели с аргументами команды. Это поведение по умолчанию.
-
OptionParser.has_option(opt_str)¶ Возвращает
True, если OptionParser имеет опцию со строкой опции opt_str (например,-qили--verbose).
-
OptionParser.remove_option(opt_str)¶ Если
OptionParserимеет опцию, соответствующую opt_str, эта опция удаляется. Если эта опция содержала какие-либо другие строки опций, все эти строки опций становятся недействительными. Если opt_str не встречается ни в одной опции, принадлежащей данномуOptionParser, возникает ошибкаValueError.
Противоречия между вариантами¶
Если вы не будете осторожны, легко определить опции с противоречивыми строками опций:
parser.add_option("-n", "--dry-run", ...)
...
parser.add_option("-n", "--noisy", ...)
(Это особенно верно, если вы определили свой собственный подкласс OptionParser с некоторыми стандартными опциями).
Каждый раз, когда вы добавляете опцию, optparse проверяет ее на наличие конфликтов с существующими опциями. Если таковые обнаруживаются, то вызывается текущий механизм обработки конфликтов. Вы можете задать механизм обработки конфликтов либо в конструкторе:
parser = OptionParser(..., conflict_handler=handler)
или с помощью отдельного вызова:
parser.set_conflict_handler(handler)
Доступными обработчиками конфликтов являются:
"error"(по умолчанию)предположить, что конфликты опций являются ошибкой программирования и поднять
OptionConflictError"resolve"грамотно разрешать конфликты опционов (см. ниже)
В качестве примера, давайте определим OptionParser, который разумно разрешает конфликты, и добавим к нему конфликтующие опции:
parser = OptionParser(conflict_handler="resolve")
parser.add_option("-n", "--dry-run", ..., help="do no harm")
parser.add_option("-n", "--noisy", ..., help="be noisy")
В этот момент optparse обнаруживает, что ранее добавленная опция уже использует строку опции -n. Поскольку conflict_handler является "resolve", он разрешает ситуацию, удаляя -n из списка строк опций предыдущей опции. Теперь --dry-run является единственным способом для пользователя активировать эту опцию. Если пользователь попросит помощи, в сообщении справки это будет отражено:
Options:
--dry-run do no harm
...
-n, --noisy be noisy
Можно уничтожить строки опций для ранее добавленной опции, пока их не останется, и у пользователя не будет возможности вызвать эту опцию из командной строки. В этом случае optparse полностью удаляет эту опцию, так что она не будет отображаться в тексте справки или где-либо еще. Продолжая работу с нашим существующим OptionParser:
parser.add_option("--dry-run", ..., help="new dry-run option")
В этот момент исходная опция -n/--dry-run уже недоступна, поэтому optparse удаляет ее, оставляя следующий текст справки:
Options:
...
-n, --noisy be noisy
--dry-run new dry-run option
Очистка¶
Экземпляры OptionParser имеют несколько циклических ссылок. Это не должно быть проблемой для сборщика мусора Python, но вы можете захотеть явно разорвать циклические ссылки, вызвав destroy() на вашем OptionParser, когда вы закончите работу с ним. Это особенно полезно в длительно работающих приложениях, где большие графы объектов доступны из вашего OptionParser.
Другие методы¶
OptionParser поддерживает несколько других публичных методов:
-
OptionParser.set_usage(usage)¶ Установите строку использования в соответствии с правилами, описанными выше для аргумента ключевого слова конструктора
usage. ПередачаNoneустанавливает строку использования по умолчанию; используйтеoptparse.SUPPRESS_USAGEдля подавления сообщения об использовании.
-
OptionParser.print_usage(file=None)¶ Выведите сообщение об использовании текущей программы (
self.usage) в file (по умолчанию stdout). Любое вхождение строки%progвself.usageзаменяется именем текущей программы. Ничего не делает, еслиself.usageпуст или не определен.
-
OptionParser.get_usage()¶ То же, что и
print_usage(), но вместо печати возвращает строку использования.
-
OptionParser.set_defaults(dest=value, ...)¶ Установите значения по умолчанию сразу для нескольких пунктов назначения опций. Использование
set_defaults()является предпочтительным способом установки значений по умолчанию для опций, так как несколько опций могут использовать один и тот же пункт назначения. Например, если несколько опций «mode» задают одно и то же место назначения, любая из них может установить значение по умолчанию, и победит последняя:parser.add_option("--advanced", action="store_const", dest="mode", const="advanced", default="novice") # overridden below parser.add_option("--novice", action="store_const", dest="mode", const="novice", default="advanced") # overrides above setting
Чтобы избежать этой путаницы, используйте
set_defaults():parser.set_defaults(mode="advanced") parser.add_option("--advanced", action="store_const", dest="mode", const="advanced") parser.add_option("--novice", action="store_const", dest="mode", const="novice")
Обратные вызовы опций¶
Когда встроенных действий и типов optparse недостаточно для ваших нужд, у вас есть два варианта: расширить optparse или определить опцию обратного вызова. Расширение optparse является более общим, но избыточным для многих простых случаев. Довольно часто простой обратный вызов - это все, что вам нужно.
Определение опции обратного вызова состоит из двух этапов:
определить саму опцию с помощью действия
"callback"написать обратный вызов; это функция (или метод), которая принимает не менее четырех аргументов, как описано ниже
Определение опции обратного вызова¶
Как всегда, самый простой способ определить опцию обратного вызова - это использовать метод OptionParser.add_option(). Кроме action, единственным атрибутом опции, который вы должны указать, является callback, функция для вызова:
parser.add_option("-c", action="callback", callback=my_callback)
callback - это функция (или другой вызываемый объект), поэтому вы должны были уже определить my_callback() при создании этой опции обратного вызова. В этом простом случае optparse даже не знает, принимает ли -c какие-либо аргументы, что обычно означает, что опция не принимает никаких аргументов - простое присутствие -c в командной строке - это все, что ей нужно знать. Однако в некоторых обстоятельствах вы можете захотеть, чтобы ваш обратный вызов потреблял произвольное количество аргументов командной строки. Именно в этом случае написание обратных вызовов становится сложной задачей; об этом мы поговорим позже в этом разделе.
optparse всегда передает четыре определенных аргумента вашему обратному вызову, а дополнительные аргументы будут передаваться только в том случае, если вы укажете их через callback_args и callback_kwargs. Таким образом, минимальная сигнатура функции обратного вызова выглядит так:
def my_callback(option, opt, value, parser):
Четыре аргумента обратного вызова описаны ниже.
Существует несколько других атрибутов опции, которые вы можете указать при определении опции обратного вызова:
typeимеет свое обычное значение: как и в случае с действиями
"store"или"append", он инструктируетoptparseпотреблять один аргумент и преобразовывать его вtype. Однако вместо того, чтобы хранить преобразованное значение (значения) где-либо,optparseпередает его вашей функции обратного вызова.nargsтакже имеет свое обычное значение: если оно задано и > 1,
optparseбудет потреблятьnargsаргументов, каждый из которых должен быть преобразован вtype. Затем он передает кортеж преобразованных значений в ваш обратный вызов.callback_argsкортеж дополнительных позиционных аргументов для передачи обратному вызову
callback_kwargsсловарь дополнительных аргументов ключевых слов для передачи обратному вызову
Как вызываются обратные вызовы¶
Все обратные вызовы вызываются следующим образом:
func(option, opt_str, value, parser, *args, **kwargs)
где
optionэто экземпляр Option, который вызывает обратный вызов
opt_strэто строка опции в командной строке, которая вызывает обратный вызов. (Если была использована сокращенная длинная опция,
opt_strбудет полной, канонической строкой опции - например, если пользователь ввел--fooв командной строке как сокращение для--foobar, тоopt_strбудет"--foobar").valueэто строка опции в командной строке, которая вызывает обратный вызов. (Если была использована сокращенная длинная опция,
optparseбудет полной, канонической строкой опции - например, если пользователь ввелtypeв командной строке как сокращение дляvalue, тоtypeбудетNone).parserэто экземпляр OptionParser, управляющий всем процессом, в основном полезный потому, что вы можете получить доступ к некоторым другим интересным данным через атрибуты его экземпляра:
parser.largsтекущий список оставшихся аргументов, то есть аргументов, которые были потреблены, но не являются ни опциями, ни аргументами опций. Не стесняйтесь изменять
parser.largs, например, добавляя в него дополнительные аргументы. (Этот список станетargs, вторым возвращаемым значениемparse_args()).parser.rargsтекущий список оставшихся аргументов, т.е. с удаленными
opt_strиvalue(если применимо) и только следующими за ними аргументами. Не стесняйтесь модифицироватьparser.rargs, например, потребляя больше аргументов.parser.valuesобъект, в котором по умолчанию хранятся значения опций (экземпляр optparse.OptionValues). Это позволяет обратным вызовам использовать тот же механизм, что и остальная часть
optparseдля хранения значений опций; вам не нужно возиться с глобальными файлами или закрытиями. Вы также можете получить доступ или изменить значение(я) любых опций, уже встречающихся в командной строке.
argsэто кортеж произвольных позиционных аргументов, передаваемых через атрибут опции
callback_args.kwargsэто словарь произвольных аргументов ключевых слов, передаваемых через
callback_kwargs.
Возбуждение ошибок в обратном вызове¶
Функция обратного вызова должна поднять OptionValueError, если возникли проблемы с опцией или ее аргументом(ами). optparse поймает это и завершит программу, напечатав сообщение об ошибке, которое вы предоставите на stderr. Ваше сообщение должно быть ясным, кратким, точным и содержать упоминание о неисправной опции. В противном случае пользователю будет трудно понять, что он сделал не так.
Пример обратного вызова 1: тривиальный обратный вызов¶
Вот пример опции обратного вызова, которая не принимает аргументов и просто записывает, что опция была замечена:
def record_foo_seen(option, opt_str, value, parser):
parser.values.saw_foo = True
parser.add_option("--foo", action="callback", callback=record_foo_seen)
Конечно, это можно сделать с помощью действия "store_true".
Пример обратного вызова 2: проверка опционного заказа¶
Вот чуть более интересный пример: зафиксируйте факт появления -a, но взорвитесь, если он появится после -b в командной строке.
def check_order(option, opt_str, value, parser):
if parser.values.b:
raise OptionValueError("can't use -a after -b")
parser.values.a = 1
...
parser.add_option("-a", action="callback", callback=check_order)
parser.add_option("-b", action="store_true", dest="b")
Пример обратного вызова 3: проверка опционного заказа (обобщенный)¶
Если вы хотите повторно использовать этот обратный вызов для нескольких похожих вариантов (установить флаг, но взорваться, если -b уже был замечен), его нужно немного доработать: сообщение об ошибке и флаг, который он устанавливает, должны быть обобщены.
def check_order(option, opt_str, value, parser):
if parser.values.b:
raise OptionValueError("can't use %s after -b" % opt_str)
setattr(parser.values, option.dest, 1)
...
parser.add_option("-a", action="callback", callback=check_order, dest='a')
parser.add_option("-b", action="store_true", dest="b")
parser.add_option("-c", action="callback", callback=check_order, dest='c')
Пример обратного вызова 4: проверка произвольного условия¶
Конечно, вы можете поместить туда любое условие - вы не ограничены проверкой значений уже определенных опций. Например, если у вас есть опции, которые не должны вызываться при полной луне, все, что вам нужно сделать, это следующее:
def check_moon(option, opt_str, value, parser):
if is_moon_full():
raise OptionValueError("%s option invalid when moon is full"
% opt_str)
setattr(parser.values, option.dest, 1)
...
parser.add_option("--foo",
action="callback", callback=check_moon, dest="foo")
(Определение is_moon_full() остается в качестве упражнения для читателя).
Пример обратного вызова 5: фиксированные аргументы¶
Ситуация становится немного интереснее, когда вы определяете опции обратного вызова, которые принимают фиксированное количество аргументов. Указание того, что опция обратного вызова принимает аргументы, аналогично определению опции "store" или "append": если вы определяете type, то опция принимает один аргумент, который должен быть приведен к этому типу; если вы далее определяете nargs, то опция принимает nargs аргументов.
Вот пример, который просто эмулирует стандартное действие "store":
def store_value(option, opt_str, value, parser):
setattr(parser.values, option.dest, value)
...
parser.add_option("--foo",
action="callback", callback=store_value,
type="int", nargs=3, dest="foo")
Обратите внимание, что optparse позаботится о получении 3 аргументов и преобразовании их в целые числа за вас; все, что вам нужно сделать, это сохранить их. (Или что угодно; очевидно, что для этого примера вам не нужен обратный вызов).
Пример обратного вызова 6: аргументы переменных¶
Ситуация осложняется, когда вы хотите, чтобы опция принимала переменное количество аргументов. Для этого случая вы должны написать обратный вызов, поскольку optparse не предоставляет для этого никаких встроенных возможностей. И вам придется иметь дело с некоторыми тонкостями обычного разбора командной строки Unix, которые optparse обычно обрабатывает за вас. В частности, обратные вызовы должны реализовать обычные правила для голых аргументов -- и -:
Ситуация осложняется, когда вы хотите, чтобы опция принимала переменное количество аргументов. Для этого случая вы должны написать обратный вызов, поскольку
--не предоставляет для этого никаких встроенных возможностей. И вам придется иметь дело с некоторыми тонкостями обычного разбора командной строки Unix, которые-обычно обрабатывает за вас. В частности, обратные вызовы должны реализовать обычные правила для голых аргументов и :bare
--(если не является аргументом какой-либо опции): остановить обработку командной строки и отбросить--.bare
-(если не является аргументом какой-либо опции): остановить обработку командной строки, но сохранить-(добавить его кparser.largs)
Если вам нужна опция, принимающая переменное количество аргументов, то здесь есть несколько тонких и сложных моментов, о которых нужно побеспокоиться. Точная реализация, которую вы выберете, будет основана на том, на какие компромиссы вы готовы пойти для своего приложения (вот почему optparse не поддерживает такие вещи напрямую).
Тем не менее, вот попытка сделать обратный вызов для опции с переменными аргументами:
def vararg_callback(option, opt_str, value, parser):
assert value is None
value = []
def floatable(str):
try:
float(str)
return True
except ValueError:
return False
for arg in parser.rargs:
# stop on --foo like options
if arg[:2] == "--" and len(arg) > 2:
break
# stop on -a, but not on -3 or -3.0
if arg[:1] == "-" and len(arg) > 1 and not floatable(arg):
break
value.append(arg)
del parser.rargs[:len(value)]
setattr(parser.values, option.dest, value)
...
parser.add_option("-c", "--callback", dest="vararg_attr",
action="callback", callback=vararg_callback)
Расширение optparse¶
Поскольку двумя основными факторами, определяющими то, как optparse интерпретирует опции командной строки, являются действие и тип каждой опции, наиболее вероятным направлением расширения является добавление новых действий и новых типов.
Добавление новых типов¶
Чтобы добавить новые типы, необходимо определить свой собственный подкласс класса optparse Option. Этот класс имеет несколько атрибутов, определяющих типы optparse: TYPES и TYPE_CHECKER.
-
Option.TYPES¶ Кортеж имен типов; в своем подклассе просто определите новый кортеж
TYPES, который основывается на стандартном.
-
Option.TYPE_CHECKER¶ Словарь, отображающий имена типов на функции проверки типов. Функция проверки типов имеет следующую сигнатуру:
def check_mytype(option, opt, value)
Чтобы добавить новые типы, необходимо определить свой собственный подкласс класса
optionOption. Этот класс имеет несколько атрибутов, которые определяют типыopt:-fиvalue.Ваша функция проверки типов должна выдать сообщение
OptionValueError, если она столкнется с какими-либо проблемами.OptionValueErrorпринимает единственный строковый аргумент, который передается как есть методуOptionParsererror(), который, в свою очередь, добавляет имя программы и строку"error:"и печатает все в stderr перед завершением процесса.
Вот глупый пример, демонстрирующий добавление типа опции "complex" для анализа комплексных чисел в стиле Python в командной строке. (Это еще глупее, чем было раньше, потому что в версии optparse 1.3 добавлена встроенная поддержка комплексных чисел, но не важно).
Во-первых, необходимый импорт:
from copy import copy
from optparse import Option, OptionValueError
Сначала вам нужно определить ваш средство проверки типов, поскольку на него будут ссылаться позже (в атрибуте класса TYPE_CHECKER вашего подкласса Option):
def check_complex(option, opt, value):
try:
return complex(value)
except ValueError:
raise OptionValueError(
"option %s: invalid complex value: %r" % (opt, value))
Наконец, подкласс Option:
class MyOption (Option):
TYPES = Option.TYPES + ("complex",)
TYPE_CHECKER = copy(Option.TYPE_CHECKER)
TYPE_CHECKER["complex"] = check_complex
(Если бы мы не сделали copy() из Option.TYPE_CHECKER, мы бы в итоге изменили атрибут TYPE_CHECKER класса Option класса optparse. Это Python, и ничто не мешает вам сделать это, кроме хороших манер и здравого смысла).
Вот и все! Теперь вы можете написать сценарий, использующий новый тип опции, как и любой другой сценарий на основе optparse, за исключением того, что вы должны указать OptionParser использовать MyOption вместо Option:
parser = OptionParser(option_class=MyOption)
parser.add_option("-c", type="complex")
В качестве альтернативы вы можете составить свой собственный список опций и передать его OptionParser; если вы не используете add_option() в вышеописанном способе, вам не нужно указывать OptionParser, какой класс опций использовать:
option_list = [MyOption("-c", action="store", type="complex", dest="c")]
parser = OptionParser(option_list=option_list)
Добавление новых действий¶
Добавление новых действий немного сложнее, потому что вы должны понимать, что optparse имеет несколько классификаций для действий:
- действия «магазина»
действия, в результате которых
optparseсохраняется значение для атрибута текущего экземпляра OptionValues; эти опции требуют, чтобы атрибутdestбыл предоставлен конструктору Option.- «набранные» действия
действия, которые принимают значение из командной строки и ожидают, что оно будет определенного типа; точнее, строка, которая может быть преобразована к определенному типу. Эти опции требуют атрибута
typeв конструкторе Option.
действия, которые принимают значение из командной строки и ожидают, что оно будет определенного типа; точнее, строка, которая может быть преобразована к определенному типу. Эти опции требуют атрибута "store" в конструкторе Option.
Когда вы добавляете действие, вам необходимо классифицировать его, включив его хотя бы в один из следующих атрибутов класса Option (все они являются списками строк):
-
Option.ACTIONS¶ Все действия должны быть перечислены в разделе ACTIONS.
-
Option.STORE_ACTIONS¶ Действия «хранить» дополнительно перечислены здесь.
-
Option.TYPED_ACTIONS¶ «Набранные» действия дополнительно перечислены здесь.
-
Option.ALWAYS_TYPED_ACTIONS¶ Действия, которые всегда принимают тип (т.е. чьи опции всегда принимают значение), дополнительно перечислены здесь. Единственный эффект этого заключается в том, что
optparseприсваивает тип по умолчанию,"string", опциям без явного типа, действие которых перечислено вALWAYS_TYPED_ACTIONS.
Для того чтобы действительно реализовать ваше новое действие, вы должны переопределить метод Option take_action() и добавить case, который распознает ваше действие.
Например, добавим действие "extend". Оно похоже на стандартное действие "append", но вместо того, чтобы принимать одно значение из командной строки и добавлять его к существующему списку, "extend" будет принимать несколько значений в одной строке, разделенной запятыми, и расширять ими существующий список. То есть, если --names является опцией "extend" типа "string", то командная строка
--names=foo,bar --names blah --names ding,dong
приведет к списку
["foo", "bar", "blah", "ding", "dong"]
И снова мы определяем подкласс Option:
class MyOption(Option):
ACTIONS = Option.ACTIONS + ("extend",)
STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
ALWAYS_TYPED_ACTIONS = Option.ALWAYS_TYPED_ACTIONS + ("extend",)
def take_action(self, action, dest, opt, value, values, parser):
if action == "extend":
lvalue = value.split(",")
values.ensure_value(dest, []).extend(lvalue)
else:
Option.take_action(
self, action, dest, opt, value, values, parser)
Особенности:
"extend"как ожидает значение в командной строке, так и сохраняет его где-то, поэтому оно входит и вSTORE_ACTIONS, и вTYPED_ACTIONS.чтобы убедиться, что
optparseприсваивает действиям"string"тип по умолчанию"extend", мы помещаем действие"extend"также вALWAYS_TYPED_ACTIONS.MyOption.take_action()реализует только это новое действие, и передает управление обратноOption.take_action()для стандартных действийoptparse.valuesявляется экземпляром класса optparse_parser.Values, который предоставляет очень полезный методensure_value().ensure_value()по сути являетсяgetattr()с предохранительным клапаном; он вызывается какvalues.ensure_value(attr, value)
Если атрибут
attrвvaluesне существует или равенNone, то функция ensure_value() сначала устанавливает его вvalue, а затем возвращает „значение“. Это очень удобно для таких действий, как"extend","append"и"count", которые накапливают данные в переменной и ожидают, что эта переменная будет определенного типа (список для первых двух, целое число для последнего). Использованиеensure_value()означает, что сценариям, использующим ваше действие, не нужно беспокоиться об установке значения по умолчанию для рассматриваемых опциональных направлений; они могут просто оставить значение по умолчаниюNone, аensure_value()позаботится о том, чтобы все было правильно, когда это потребуется.