> **Источник:** https://python-all.ru/3.0/library/optparse.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# `optparse` – более мощный парсер опций командной строки

`optparse` – более удобная, гибкая и мощная библиотека для разбора опций командной строки, чем старый модуль [`getopt`](https://python-all.ru/3.0/library/getopt.html#module-getopt). `optparse` использует более декларативный стиль разбора командной строки: создаётся экземпляр `OptionParser`, заполняется опциями и выполняется разбор командной строки. `optparse` позволяет пользователям задавать опции в традиционном синтаксисе GNU/POSIX, а также автоматически генерирует сообщения об использовании и справку.

Вот пример использования `optparse` в простом скрипте:

```python
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()
```

С помощью этих нескольких строк кода пользователи вашего скрипта теперь могут делать «обычные вещи» в командной строке, например:

```python
<yourscript> --file=outfile -q
```

При разборе командной строки `optparse` устанавливает атрибуты объекта `options`, возвращаемого функцией `parse_args()`, на основе значений, указанных пользователем в командной строке. Когда `parse_args()` завершает разбор, `options.filename` будет равно `"outfile"`, а `options.verbose` – `False`. `optparse` поддерживает как длинные, так и короткие опции, позволяет объединять короткие опции и связывать опции с их аргументами различными способами. Таким образом, следующие командные строки эквивалентны приведённому выше примеру:

```python
<yourscript> -f outfile --quiet
<yourscript> --quiet --file outfile
<yourscript> -q -foutfile
<yourscript> -qfoutfile
```

Кроме того, можно запустить один из

```python
<yourscript> -h
<yourscript> --help
```

и `optparse` выведет краткую сводку опций вашего скрипта:

```python
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` и никогда не будут. Это сделано намеренно: первые три нестандартны в любом окружении, а последний имеет смысл только в том случае, если программа ориентирована исключительно на VMS, MS-DOS и/или Windows.

**аргумент опции**

аргумент, который следует за опцией, тесно связан с этой опцией и извлекается из списка аргументов вместе с ней. В `optparse` аргументы опций могут находиться как в отдельном аргументе от своей опции:

```python
-f foo
--file foo
```

или включены в тот же аргумент:

```python
-ffoo
--file=foo
```

Обычно у опции либо есть аргумент, либо нет. Многие хотят иметь возможность «необязательных аргументов опции», то есть некоторые опции будут принимать аргумент, если он есть, и не будут, если его нет. Это несколько спорно, потому что делает разбор неоднозначным: если `"-a"` принимает необязательный аргумент, а `"-b"` – это совсем другая опция, как интерпретировать `"-ab"`? Из-за этой неоднозначности `optparse` не поддерживает такую возможность.

**позиционный аргумент**

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

**обязательная опция**

опция, которая должна быть указана в командной строке; обратите внимание, что фраза «обязательная опция» внутренне противоречива.

`optparse`

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

`examples/required_1.py`

и

`examples/required_2.py`

в дистрибутиве исходного кода

`optparse`

для двух способов реализации обязательных опций с помощью

`optparse`

.

Например, рассмотрим эту гипотетическую командную строку:

```python
prog -v --report /tmp/report.txt foo bar
```

`"-v"` и `"--report"` – это опции. Если предположить, что *--report* принимает один аргумент, то `"/tmp/report.txt"` – это аргумент опции. `"foo"` и `"bar"` – это позиционные аргументы.

### Для чего нужны опции?

Опции используются для предоставления дополнительной информации для настройки или кастомизации выполнения программы. На всякий случай, если это не было очевидно: опции обычно *необязательны*. Программа должна нормально работать вообще без опций. (Выберите случайную программу из набора Unix или GNU. Может ли она работать вообще без опций и при этом иметь смысл? Основные исключения – `find`, `tar` и `dd` – все они являются мутантными чудаками, которые справедливо критикуются за нестандартный синтаксис и запутанные интерфейсы.)

Многие хотят, чтобы в их программах были «обязательные опции». Подумайте об этом. Если это обязательно, значит, это *не необязательно*! Если есть информация, которая absolutely необходима вашей программе для успешного выполнения, для этого существуют позиционные аргументы.

В качестве примера хорошего дизайна интерфейса командной строки рассмотрим скромную утилиту `cp` для копирования файлов. Не имеет особого смысла пытаться копировать файлы без указания назначения и хотя бы одного источника. Следовательно, `cp` завершается ошибкой, если запустить её без аргументов. Однако у неё гибкий, полезный синтаксис, который вообще не требует никаких опций:

```python
cp SOURCE DEST
cp SOURCE ... DEST-DIR
```

С этим можно зайти довольно далеко. Большинство реализаций `cp` предоставляют множество опций для точной настройки копирования: можно сохранять режим и время изменения, избегать следования симлинкам, спрашивать подтверждение перед перезаписью существующих файлов и т.д. Но ничто из этого не отвлекает от основной миссии `cp`, которая состоит в копировании одного файла в другой или нескольких файлов в другой каталог.

### Для чего нужны позиционные аргументы?

Позиционные аргументы предназначены для тех частей информации, которые absolutely и однозначно необходимы вашей программе для работы.

Хороший пользовательский интерфейс должен иметь как можно меньше абсолютных требований. Если вашей программе требуется 17 различных частей информации для успешного запуска, не имеет большого значения *как* вы получаете эту информацию от пользователя – большинство людей сдадутся и уйдут, так и не запустив программу. Это справедливо независимо от того, является ли интерфейс командной строкой, файлом конфигурации или графическим интерфейсом: если вы предъявляете столько требований к пользователям, большинство из них просто сдадутся.

Короче говоря, старайтесь минимизировать объем информации, которую пользователи absolutely обязаны предоставить – используйте разумные значения по умолчанию, когда это возможно. Конечно, вы также хотите сделать свои программы достаточно гибкими. Для этого и нужны опции. Опять же, неважно, являются ли они записями в файле конфигурации, виджетами в диалоге «Настройки» графического интерфейса или опциями командной строки – чем больше опций вы реализуете, тем гибче становится ваша программа, и тем сложнее становится ее реализация. Слишком большая гибкость тоже имеет недостатки; слишком много опций может перегрузить пользователей и сделать ваш код гораздо сложнее в поддержке.

## Учебное руководство

Хотя `optparse` довольно гибок и мощен, в большинстве случаев он достаточно прост в использовании. В этом разделе рассматриваются шаблоны кода, общие для любой программы на основе `optparse`.

Сначала необходимо импортировать класс OptionParser; затем, в начале основной программы, создать экземпляр OptionParser:

```python
from optparse import OptionParser
[...]
parser = OptionParser()
```

Затем можно приступить к определению опций. Базовый синтаксис:

```python
parser.add_option(opt_str, ...,
                  attr=value, ...)
```

Каждая опция имеет одну или несколько строк опции, например `"-f"` или `"--file"`, и несколько атрибутов опции, которые сообщают `optparse`, чего ожидать и что делать, когда он встречает эту опцию в командной строке.

Обычно каждая опция имеет одну короткую и одну длинную строку опции, например:

```python
parser.add_option("-f", "--file", ...)
```

Вы можете определить любое количество коротких и длинных строк опций (включая ноль), при условии, что в целом есть хотя бы одна строка опции.

Строки опций, передаваемые в `add_option()`, по сути являются метками для опции, определённой этим вызовом. Для краткости мы часто будем говорить о *встрече опции* в командной строке; на самом деле `optparse` встречает *строки опций* и ищет по ним опции.

Когда все опции определены, укажите `optparse` разобрать командную строку вашей программы:

```python
(options, args) = parser.parse_args()
```

(При желании можно передать собственный список аргументов в `parse_args()`, но это редко бывает необходимо: по умолчанию используется `sys.argv[1:]`.)

`parse_args()` возвращает два значения:

- `options` – объект, содержащий значения для всех опций; например, если `"--file"` принимает единственный строковой аргумент, то `options.file` будет именем файла, указанным пользователем, или `None`, если пользователь не указал эту опцию.
- `args` – список позиционных аргументов, оставшихся после разбора опций.

В этом разделе руководства рассматриваются только четыре наиболее важных атрибута опции: `action`, [`type`](https://python-all.ru/3.0/library/functions.html#type), `dest` (назначение) и [`help`](https://python-all.ru/3.0/library/functions.html#help). Из них `action` является основным.

### Понимание действий опций

Действия сообщают `optparse`, что делать, когда он встречает опцию в командной строке. Существует фиксированный набор действий, жёстко заданный в `optparse`; добавление новых действий – продвинутая тема, рассматриваемая в разделе [*Расширение optparse*](https://python-all.ru/3.0/library/optparse.html#optparse-extending-optparse). Большинство действий указывают `optparse` сохранить значение в некоторой переменной – например, взять строку из командной строки и сохранить её в атрибуте `options`.

Если не указать действие опции, `optparse` по умолчанию использует `store`.

### Действие store

Наиболее распространённое действие опции – `store`, которое указывает `optparse` взять следующий аргумент (или остаток текущего аргумента), убедиться, что он имеет правильный тип, и сохранить его в выбранное вами назначение.

Например:

```python
parser.add_option("-f", "--file",
                  action="store", type="string", dest="filename")
```

Теперь создадим фиктивную командную строку и попросим `optparse` разобрать её:

```python
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`. Вот опция, ожидающая целочисленный аргумент:

```python
parser.add_option("-n", type="int", dest="num")
```

Обратите внимание, что эта опция не имеет длинной строки опции, что вполне допустимо. Кроме того, нет явного действия, поскольку по умолчанию используется `store`.

Разберём ещё одну тестовую командную строку. На этот раз поместим аргумент опции непосредственно рядом с опцией: поскольку `"-n42"` (один аргумент) эквивалентно `"-n 42"` (два аргумента), код

```python
(options, args) = parser.parse_args(["-n42"])
print(options.num)
```

выведет `"42"`.

Если не указать тип, `optparse` предполагает `string`. В сочетании с тем, что действие по умолчанию – `store`, это означает, что наш первый пример можно значительно сократить:

```python
parser.add_option("-f", "--file", dest="filename")
```

Если не указать назначение, `optparse` определяет разумное значение по умолчанию из строк опции: если первой длинной строкой опции является `"--foo-bar"`, то назначением по умолчанию будет `foo_bar`. Если длинных строк опции нет, `optparse` смотрит на первую короткую строку опции: назначение по умолчанию для `"-f"` – `f`.

`optparse` также включает встроенный тип `complex`. Добавление типов описано в разделе [*Extending optparse*](https://python-all.ru/3.0/library/optparse.html#optparse-extending-optparse).

### Обработка булевых (флаговых) опций

Опции-флаги – установка переменной в true или false при встрече определённой опции – довольно распространены. `optparse` поддерживает их с помощью двух отдельных действий: `store_true` и `store_false`. Например, может быть флаг `verbose`, который включается с помощью `"-v"` и выключается с помощью `"-q"`:

```python
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`**

увеличить счётчик на единицу

**`колбэк`**

вызвать указанную функцию

Эти вопросы рассматриваются в разделе [*Справочное руководство*](https://python-all.ru/3.0/library/optparse.html#optparse-reference-guide), Справочное руководство и разделе [*Колбэки опций*](https://python-all.ru/3.0/library/optparse.html#optparse-option-callbacks).

### Значения по умолчанию

Все приведённые выше примеры подразумевают установку некоторой переменной (так называемого «назначения») при встрече определённых параметров командной строки. Что произойдёт, если эти параметры ни разу не встретятся? Поскольку мы не указали значения по умолчанию, все они будут установлены в `None`. Обычно это нормально, но иногда хочется большего контроля. `optparse` позволяет указать значение по умолчанию для каждого назначения; оно присваивается до разбора командной строки.

Сначала рассмотрим пример verbose/quiet. Если нужно, чтобы `optparse` устанавливал `verbose` в `True`, если только не встретится `"-q"`, то можно сделать следующее:

```python
parser.add_option("-v", action="store_true", dest="verbose", default=True)
parser.add_option("-q", action="store_false", dest="verbose")
```

Поскольку значения по умолчанию применяются к *назначению*, а не к какому-либо конкретному параметру, и эти два параметра имеют одно и то же назначение, это полностью эквивалентно:

```python
parser.add_option("-v", action="store_true", dest="verbose")
parser.add_option("-q", action="store_false", dest="verbose", default=True)
```

Рассмотрим это:

```python
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()`:

```python
parser.set_defaults(verbose=True)
parser.add_option(...)
(options, args) = parser.parse_args()
```

Как и прежде, последнее указанное значение для данного назначения параметра и будет использоваться. Для ясности старайтесь использовать какой-то один способ задания значений по умолчанию, а не оба сразу.

### Генерация справки

Возможность `optparse` автоматически создавать текст справки и описание использования полезна для создания удобных интерфейсов командной строки. Всё, что нужно сделать, – указать значение [`help`](https://python-all.ru/3.0/library/functions.html#help) для каждой опции и, при желании, краткое сообщение об использовании для всей программы. Вот OptionParser, заполненный удобными (документированными) опциями:

```python
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()`, он выводит следующее на стандартный вывод:

```python
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]
```

(Если вывод справки вызван параметром помощи, `optparse` завершает работу после печати текста справки.)

Здесь задействовано много всего, чтобы помочь `optparse` сгенерировать наилучшее сообщение справки:

- сценарий определяет собственное сообщение об использовании:

  ```python
  usage = "usage: %prog [options] arg1 arg2"
  ```

  `optparse` заменяет `"%prog"` в строке использования на имя текущей программы, то есть `os.path.basename(sys.argv[0])`. Затем расширенная строка выводится перед подробной справкой по опциям.

  Если строка usage не указана, `optparse` использует стандартное, но вполне разумное значение: `"usage: %prog [options]"`. Это подходит, если скрипт не принимает позиционные аргументы.
- каждый параметр определяет строку справки, и не нужно беспокоиться о переносе строк – `optparse` заботится о переносе строк и о том, чтобы вывод справки выглядел хорошо.
- Опции, принимающие значение, указывают на это в автоматически сгенерированном сообщении справки, например, для опции «mode»:

  ```python
  -m MODE, --mode=MODE
  ```

  Здесь «MODE» называется мета-переменной: она обозначает аргумент, который пользователь должен передать [*-m*](https://python-all.ru/3.0/using/cmdline.html#cmdoption-m)/*--mode*. По умолчанию `optparse` преобразует имя переменной назначения в верхний регистр и использует его для мета-переменной. Иногда это не то, что нужно – например, опция *--filename* явно задаёт `metavar="FILE"`, что приводит к следующему автоматически сгенерированному описанию опции:

  ```python
  -f FILE, --filename=FILE
  ```

  Это важно не только для экономии места: написанный вручную текст справки использует мета-переменную «FILE», чтобы дать пользователю понять, что существует связь между полуформальным синтаксисом «-f FILE» и неформальным семантическим описанием «write output to FILE». Это простой, но эффективный способ сделать текст справки значительно понятнее и полезнее для конечных пользователей.
- параметры, имеющие значение по умолчанию, могут включать `%default` в строку справки – `optparse` заменит его на [`str()`](https://python-all.ru/3.0/library/functions.html#str) от значения по умолчанию параметра. Если у параметра нет значения по умолчанию (или значение по умолчанию – `None`), `%default` разворачивается в `none`.

При работе с большим количеством опций удобно группировать их для улучшения вывода справки. Один `OptionParser` может содержать несколько групп опций, каждая из которых может включать несколько опций.

Продолжая работать с анализатором, определённым выше, добавить `OptionGroup` в анализатор очень просто:

```python
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)
```

Это приведёт к следующему выводу справки:

```python
usage:  [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)
  -fFILE, --file=FILE  write output to FILE
  -mMODE, --mode=MODE  interaction mode: one of 'novice', 'intermediate'
                       [default], 'expert'

  Dangerous Options:
  Caution: use of these options is at your own risk.  It is believed that
  some of them bite.
  -g                 Group option.
```

### Печать строки версии

Подобно краткой строке использования, `optparse` также может выводить строку версии для вашей программы. Нужно указать эту строку в качестве аргумента `version` для OptionParser:

```python
parser = OptionParser(usage="%prog [-f] [-q]", version="%prog 1.0")
```

`"%prog"` is expanded just like it is in `usage`. Apart from that, `version` can contain anything you like. When you supply it, `optparse` automatically adds a `"--version"` option to your parser. If it encounters this option on the command line, it expands your `version` string (by replacing `"%prog"`), prints it to stdout, and exits.

Например, если ваш скрипт называется `/usr/bin/foo`:

```python
$ /usr/bin/foo --version
foo 1.0
```

### Как `optparse` обрабатывает ошибки

`optparse` имеет дело с двумя широкими классами ошибок: ошибками программиста и ошибками пользователя. Ошибки программиста обычно возникают из-за некорректных вызовов `parser.add_option()`, например, недопустимые строки опций, неизвестные атрибуты опций, отсутствующие атрибуты и т.д. Они обрабатываются обычным способом: выбрасывается исключение (`optparse.OptionError` или [`TypeError`](https://python-all.ru/3.0/library/exceptions.html#exceptions.TypeError)), и программа завершается крахом.

Обработка ошибок пользователя гораздо важнее, поскольку они гарантированно будут возникать независимо от стабильности кода. `optparse` может автоматически обнаруживать некоторые ошибки пользователя, такие как неверные аргументы опций (передача `"-n 4x"`, где *-n* ожидает целочисленный аргумент), отсутствие аргументов (`"-n"` в конце командной строки, где *-n* принимает аргумент любого типа). Кроме того, можно вызвать `parser.error()`, чтобы сообщить об ошибке, определённой приложением:

```python
(options, args) = parser.parse_args()
[...]
if options.a and options.b:
    parser.error("options -a and -b are mutually exclusive")
```

В любом случае `optparse` обрабатывает ошибку одинаково: выводит справку по использованию программы и сообщение об ошибке в стандартный поток ошибок и завершается с кодом ошибки 2.

Рассмотрим первый пример выше, где пользователь передаёт `"4x"` опции, ожидающей целое число:

```python
$ /usr/bin/foo -n 4x
usage: foo [options]

foo: error: option -n: invalid integer value: '4x'
```

Или когда пользователь вообще не передаёт значение:

```python
$ /usr/bin/foo -n
usage: foo [options]

foo: error: -n option requires an argument
```

Сообщения об ошибках, сгенерированные `optparse`, всегда указывают опцию, связанную с ошибкой; обязательно делайте то же самое при вызове `parser.error()` из кода приложения.

Если поведение `optparse` по умолчанию при обработке ошибок не соответствует вашим требованиям, потребуется создать подкласс OptionParser и переопределить его методы [`exit()`](https://python-all.ru/3.0/library/constants.html#exit) и/или `error()`.

### Собираем всё вместе

Вот как обычно выглядят сценарии на основе `optparse`:

```python
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:

```python
parser = OptionParser(...)
```

Конструктор OptionParser не имеет обязательных аргументов, но принимает ряд необязательных именованных аргументов. Всегда передавайте их как именованные аргументы, то есть не полагайтесь на порядок объявления аргументов.

> **`usage` (по умолчанию: `"%prog [options]"`)**
>
> Краткое описание использования (usage), которое выводится при неверном запуске программы или при запросе справки. Когда
>
> `optparse`
>
> выводит строку usage, он заменяет
>
> `%prog`
>
> на
>
> `os.path.basename(sys.argv[0])`
>
> (или на
>
> `prog`
>
> , если был передан этот именованный аргумент). Чтобы отключить вывод сообщения usage, передайте специальное значение
>
> `optparse.SUPPRESS_USAGE`
>
> .
>
> **`option_list` (по умолчанию: `[]`)**
>
> Список объектов Option для заполнения анализатора. Опции из
>
> `option_list`
>
> добавляются после всех опций из
>
> `standard_option_list`
>
> (атрибут класса, который может быть установлен подклассами OptionParser), но перед любыми опциями версии или справки. Устарело; используйте
>
> `add_option()`
>
> после создания анализатора.
>
> **`option_class` (по умолчанию: optparse.Option)**
>
> Класс, используемый при добавлении опций в анализатор с помощью
>
> `add_option()`
>
> .
>
> **`version` (по умолчанию: `None`)**
>
> Строка версии, которая выводится, когда пользователь указывает опцию версии. Если передать истинное значение для
>
> `version`
>
> ,
>
> `optparse`
>
> автоматически добавляет опцию версии с единственной строкой опции
>
> `"--version"`
>
> . Подстрока
>
> `"%prog"`
>
> раскрывается так же, как и для
>
> `usage`
>
> .
>
> **`conflict_handler` (по умолчанию: `"error"`)**
>
> Определяет поведение при добавлении опций с конфликтующими строками опций; см. раздел
>
> [*Конфликты между опциями*](https://python-all.ru/3.0/library/optparse.html#optparse-conflicts-between-options)
>
> .
>
> **`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])`
>
> .

### Заполнение парсера

Существует несколько способов заполнить анализатор опциями. Предпочтительный способ – использование `OptionParser.add_option()`, как показано в разделе [*Учебное пособие*](https://python-all.ru/3.0/library/optparse.html#optparse-tutorial). `add_option()` можно вызвать одним из двух способов:

- передать ему экземпляр Option (возвращаемый функцией `make_option()`)
- передать любую комбинацию позиционных и именованных аргументов, которые допустимы для `make_option()` (т.е. для конструктора Option), и он создаст экземпляр Option автоматически

Другой способ – передать список предварительно созданных экземпляров Option конструктору OptionParser, например:

```python
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`:

```python
parser.add_option(opt_str[, ...], attr=value, ...)
```

Для определения опции только с короткой строкой опции:

```python
parser.add_option("-f", attr=value, ...)
```

А для определения опции только с длинной строкой опции:

```python
parser.add_option("--foo", attr=value, ...)
```

Именованные аргументы определяют атрибуты нового объекта Option. Самый важный атрибут опции – `action`, и он во многом определяет, какие другие атрибуты являются уместными или обязательными. Если передать неуместные атрибуты опции или не указать обязательные, `optparse` выбрасывает исключение `OptionError` с объяснением ошибки.

Атрибут *action* опции определяет, что `optparse` делает при встрече этой опции в командной строке. Стандартные действия опций, жёстко закодированные в `optparse`:

**`store`**

сохранить аргумент опции (по умолчанию)

**`store_const`**

сохранить константное значение

**`store_true`**

сохраняет истинное значение

**`store_false`**

сохраняет ложное значение

**`append`**

добавить аргумент этой опции в список

**`append_const`**

добавить константное значение в список

**`count`**

увеличить счётчик на единицу

**`колбэк`**

вызвать указанную функцию

**[`help`](https://python-all.ru/3.0/library/functions.html#help)**

вывести сообщение об использовании, включающее все опции и документацию к ним

(Если не задано действие, по умолчанию используется `store`. Для этого действия также можно задать атрибуты опции [`type`](https://python-all.ru/3.0/library/functions.html#type) и `dest`; см. ниже.)

Как видно, большинство действий сводится к сохранению или обновлению значения где-либо. `optparse` всегда создаёт для этого специальный объект, который традиционно называется `options` (на самом деле это экземпляр `optparse.Values`). Аргументы опций (и другие значения) сохраняются как атрибуты этого объекта в соответствии с атрибутом опции `dest` (назначение).

Например, при вызове

```python
parser.parse_args()
```

одно из первых действий `optparse` – создать объект `options`:

```python
options = Values()
```

Если одна из опций в этом анализаторе определена с помощью

```python
parser.add_option("-f", "--file", action="store", type="string", dest="filename")
```

и разбираемая командная строка включает любую из следующих:

```python
-ffoo
-f foo
--file=foo
--file foo
```

затем `optparse`, увидев эту опцию, выполнит эквивалент

```python
options.filename = "foo"
```

Атрибуты опции [`type`](https://python-all.ru/3.0/library/functions.html#type) и `dest` почти так же важны, как `action`, но `action` – единственный, который имеет смысл для *всех* опций.

### Стандартные действия опций

Различные действия опций имеют несколько разные требования и эффекты. Большинство действий имеют несколько соответствующих атрибутов, которые можно указать, чтобы направить поведение `optparse`; некоторые имеют обязательные атрибуты, которые необходимо указать для любой опции, использующей это действие.

- `store` \[значимые: [`type`](https://python-all.ru/3.0/library/functions.html#type), `dest`, `nargs`, `choices`\]

  За опцией должен следовать аргумент, который преобразуется в значение согласно [`type`](https://python-all.ru/3.0/library/functions.html#type) и сохраняется в `dest`. Если `nargs` \> 1, из командной строки будет извлечено несколько аргументов; все они будут преобразованы согласно [`type`](https://python-all.ru/3.0/library/functions.html#type) и сохранены в `dest` в виде кортежа. См. раздел «Типы опций» ниже.

  Если указан `choices` (список или кортеж строк), по умолчанию используется тип `choice`.

  Если [`type`](https://python-all.ru/3.0/library/functions.html#type) не указан, по умолчанию используется `string`.

  Если `dest` не указан, `optparse` выводит назначение из первой длинной строки опции (например, `"--foo-bar"` подразумевает `foo_bar`). Если длинных строк опции нет, `optparse` выводит назначение из первой короткой строки опции (например, `"-f"` подразумевает `f`).

  Пример:

  ```python
  parser.add_option("-f")
  parser.add_option("-p", type="float", nargs=3, dest="point")
  ```

  В процессе разбора командной строки

  ```python
  -f foo.txt -p 1 -3.5 4 -fbar.txt
  ```

  `optparse` установит

  ```python
  options.f = "foo.txt"
  options.point = (1.0, -3.5, 4.0)
  options.f = "bar.txt"
  ```
- `store_const` \[обязательно: `const`; значимые: `dest`\]

  Значение `const` сохраняется в `dest`.

  Пример:

  ```python
  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` установит

  ```python
  options.verbose = 2
  ```
- `store_true` \[значимые: `dest`\]

  Частный случай `store_const`, который сохраняет истинное значение в `dest`.
- `store_false` \[значимые: `dest`\]

  Как и `store_true`, но сохраняет ложное значение.

  Пример:

  ```python
  parser.add_option("--clobber", action="store_true", dest="clobber")
  parser.add_option("--no-clobber", action="store_false", dest="clobber")
  ```
- `append` \[значимые: [`type`](https://python-all.ru/3.0/library/functions.html#type), `dest`, `nargs`, `choices`\]

  За опцией должен следовать аргумент, который добавляется в список в `dest`. Если для `dest` не задано значение по умолчанию, при первом обнаружении этой опции в командной строке `optparse` автоматически создаёт пустой список. Если `nargs` \> 1, извлекается несколько аргументов, и в `dest` добавляется кортеж длины `nargs`.

  Значения по умолчанию для [`type`](https://python-all.ru/3.0/library/functions.html#type) и `dest` такие же, как для действия `store`.

  Пример:

  ```python
  parser.add_option("-t", "--tracks", action="append", type="int")
  ```

  Если в командной строке встречается `"-t3"`, `optparse` делает то же самое, что:

  ```python
  options.tracks = []
  options.tracks.append(int("3"))
  ```

  Если чуть позже встречается `"--tracks=4"`, он делает:

  ```python
  options.tracks.append(int("4"))
  ```
- `append_const` \[обязательно: `const`; значимые: `dest`\]

  Как и `store_const`, но значение `const` добавляется в `dest`; как и в `append`, `dest` по умолчанию равен `None`, и при первом обнаружении опции автоматически создаётся пустой список.
- `count` \[значимые: `dest`\]

  Увеличивает целое число, сохранённое в `dest`. Если значение по умолчанию не задано, `dest` устанавливается в ноль перед первым увеличением.

  Пример:

  ```python
  parser.add_option("-v", action="count", dest="verbosity")
  ```

  При первом обнаружении `"-v"` в командной строке `optparse` делает то же самое, что:

  ```python
  options.verbosity = 0
  options.verbosity += 1
  ```

  Каждое последующее появление `"-v"` приводит к

  ```python
  options.verbosity += 1
  ```
- `колбэк` \[обязательно: `колбэк`; связанные: [`type`](https://python-all.ru/3.0/library/functions.html#type), `nargs`, `callback_args`, `callback_kwargs`\]

  Вызывает функцию, заданную `колбэк`, которая вызывается как

  ```python
  func(option, opt_str, value, parser, *args, **kwargs)
  ```

  Смотрите раздел [*Колбэки опций*](https://python-all.ru/3.0/library/optparse.html#optparse-option-callbacks) для подробностей.
- [`справка`](https://python-all.ru/3.0/library/functions.html#help)

  Печатает полное сообщение справки для всех опций текущего анализатора опций. Сообщение справки формируется из строки `usage`, переданной конструктору OptionParser, и строки [`справка`](https://python-all.ru/3.0/library/functions.html#help), переданной каждой опции.

  Если для опции не указана строка [`справка`](https://python-all.ru/3.0/library/functions.html#help), она всё равно будет показана в сообщении справки. Чтобы полностью исключить опцию, используйте специальное значение `optparse.SUPPRESS_HELP`.

  `optparse` автоматически добавляет опцию [`справка`](https://python-all.ru/3.0/library/functions.html#help) во все объекты OptionParser, поэтому обычно нет необходимости создавать её вручную.

  Пример:

  ```python
  from optparse import OptionParser, SUPPRESS_HELP

  parser = OptionParser()
  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"`):

  ```python
  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)`.
- `версия`

  Печатает номер версии, переданный OptionParser, в stdout и завершает работу. Номер версии форматируется и печатается методом `print_version()` класса OptionParser. Обычно имеет смысл только если аргумент `version` передан конструктору OptionParser. Как и с опциями [`справка`](https://python-all.ru/3.0/library/functions.html#help), вы редко будете создавать опции `версия`, поскольку `optparse` автоматически добавляет их при необходимости.

### Атрибуты опций

Следующие атрибуты опций могут быть переданы как именованные аргументы в `parser.add_option()`. Если передать атрибут, не соответствующий данной опции, или не передать обязательный атрибут опции, `optparse` возбуждает `OptionError`.

- `действие` (по умолчанию: `"store"`)

  Определяет поведение `optparse` при обнаружении этой опции в командной строке; доступные варианты описаны выше.
- [`тип`](https://python-all.ru/3.0/library/functions.html#type) (по умолчанию: `"string"`)

  Тип аргумента, ожидаемый этой опцией (например, `"string"` или `"int"`); доступные типы опций описаны ниже.
- `назначение` (по умолчанию: выводится из строк опции)

  Если действие опции подразумевает запись или изменение какого-либо значения, этот атрибут указывает `optparse`, куда его записать: `назначение` задаёт атрибут объекта `options`, который `optparse` создаёт при разборе командной строки.
- `default` (устарело)

  Значение, используемое для назначения этой опции, если опция не обнаружена в командной строке. Устарело; вместо этого используйте `parser.set_defaults()`.
- `nargs` (по умолчанию: 1)

  Сколько аргументов типа [`тип`](https://python-all.ru/3.0/library/functions.html#type) должно быть обработано при обнаружении этой опции. Если \> 1, `optparse` сохранит кортеж значений в `назначение`.
- `константа`

  Для действий, сохраняющих постоянное значение, – само это постоянное значение.
- `варианты_выбора`

  Для опций типа `"choice"` – список строк, из которых пользователь может выбирать.
- `колбэк`

  Для опций с действием `"колбэк"` – вызываемый объект, который вызывается при обнаружении этой опции. Подробнее об аргументах, передаваемых в `callable`, см. раздел [*Колбэки опций*](https://python-all.ru/3.0/library/optparse.html#optparse-option-callbacks).
- `callback_args`, `callback_kwargs`

  Дополнительные позиционные и именованные аргументы для передачи в `колбэк` после четырёх стандартных аргументов колбэка.
- [`справка`](https://python-all.ru/3.0/library/functions.html#help)

  Текст справки для этой опции, выводимый при перечислении всех доступных опций после того, как пользователь укажет опцию [`справка`](https://python-all.ru/3.0/library/functions.html#help) (например, `"--help"`). Если текст справки не указан, опция будет выведена без текста. Чтобы скрыть эту опцию, используйте специальное значение `SUPPRESS_HELP`.
- `метапеременная` (по умолчанию: выводится из строк опции)

  Замена для аргумента(ов) опции, используемая при выводе текста справки. Пример см. в разделе [*Учебник*](https://python-all.ru/3.0/library/optparse.html#optparse-tutorial).

### Стандартные типы опций

`optparse` имеет пять встроенных типов опций: `string`, `int`, `choice`, `float` и `complex`. Если вам нужно добавить новые типы опций, обратитесь к разделу [*Расширение optparse*](https://python-all.ru/3.0/library/optparse.html#optparse-extending-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()`:

```python
(options, args) = parser.parse_args(args=None, values=None)
```

где входные параметры:

**`args`**

список аргументов для обработки (по умолчанию:

`sys.argv[1:]`

)

**`values`**

объект для хранения аргументов опций (по умолчанию: новый экземпляр optparse.Values)

а возвращаемые значения –

**`options`**

тот же объект, который был передан как

`options`

, или экземпляр optparse.Values, созданный

`optparse`

**`args`**

оставшиеся позиционные аргументы после обработки всех опций

Наиболее распространённый способ – не указывать ни один из именованных аргументов. Если указать `options`, он будет изменён многократными вызовами `setattr()` (примерно по одному на каждый аргумент опции, сохранённый в назначении опции) и возвращён `parse_args()`.

Если `parse_args()` встречает какие-либо ошибки в списке аргументов, он вызывает метод `error()` класса OptionParser с соответствующим сообщением об ошибке для конечного пользователя. Это в конечном итоге приводит к завершению процесса с кодом выхода 2 (традиционный код выхода Unix для ошибок командной строки).

### Запросы и изменение вашего парсера опций

Поведение анализатора опций по умолчанию можно немного настроить, а также можно исследовать анализатор опций и посмотреть, что в нём есть. OptionParser предоставляет несколько методов, которые помогут:

**`disable_interspersed_args()`**

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

**`enable_interspersed_args()`**

Устанавливает режим разбора, при котором разбор не останавливается на первом не-опционном аргументе, позволяя перемешивать флаги с аргументами команды. Например,

`"-s arg1 --long arg2"`

вернёт

`["arg1", "arg2"]`

в качестве аргументов команды, а

`-s, --long`

– как опции. Это поведение по умолчанию.

**`get_option(opt_str)`**

Возвращает экземпляр Option с опционной строкой

`opt_str`

или

`None`

, если ни одна опция не имеет такой опционной строки.

**`has_option(opt_str)`**

Возвращает true, если OptionParser имеет опцию с опционной строкой

`opt_str`

(например,

`"-q"`

или

`"--verbose"`

).

**`remove_option(opt_str)`**

Если

`OptionParser`

содержит опцию, соответствующую

`opt_str`

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

`opt_str`

не встречается ни в одной опции, принадлежащей этому

`OptionParser`

, возбуждается

[`ValueError`](https://python-all.ru/3.0/library/exceptions.html#exceptions.ValueError)

.

### Конфликты между опциями

Если быть невнимательным, легко определить опции с конфликтующими строками опций:

```python
parser.add_option("-n", "--dry-run", ...)
[...]
parser.add_option("-n", "--noisy", ...)
```

(Это особенно актуально, если определён собственный подкласс OptionParser с некоторыми стандартными опциями.)

Каждый раз при добавлении опции `optparse` проверяет конфликты с существующими опциями. Если они находятся, вызывается текущий механизм разрешения конфликтов. Можно задать механизм разрешения конфликтов либо в конструкторе:

```python
parser = OptionParser(..., conflict_handler=handler)
```

или отдельным вызовом:

```python
parser.set_conflict_handler(handler)
```

Доступные обработчики конфликтов:

> **`error` (по умолчанию)**
>
> предполагать, что конфликты опций являются ошибкой программирования, и возбуждать
>
> `OptionConflictError`
>
> **`resolve`**
>
> разрешать конфликты опций интеллектуально (см. ниже)

В качестве примера давайте определим `OptionParser`, который разрешает конфликты интеллектуально, и добавим к нему конфликтующие опции:

```python
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"` – единственный способ для пользователя активировать эту опцию. Если пользователь запросит справку, сообщение справки отразит это:

```python
options:
  --dry-run     do no harm
  [...]
  -n, --noisy   be noisy
```

Можно сокращать строки опций для ранее добавленной опции, пока их не останется, и у пользователя не будет возможности вызвать эту опцию из командной строки. В этом случае `optparse` полностью удаляет эту опцию, так что она не появляется в тексте справки или где-либо ещё. Продолжая с нашим существующим OptionParser:

```python
parser.add_option("--dry-run", ..., help="new dry-run option")
```

На этом этапе исходная опция *-n/--dry-run* больше недоступна, поэтому `optparse` удаляет её, оставляя такой текст справки:

```python
options:
  [...]
  -n, --noisy   be noisy
  --dry-run     new dry-run option
```

### Очистка

Экземпляры OptionParser имеют несколько циклических ссылок. Это не должно быть проблемой для сборщика мусора Python, но вы можете захотеть разорвать циклические ссылки явно, вызвав `destroy()` на вашем OptionParser, когда закончите с ним работать. Это особенно полезно в долго работающих приложениях, где большие графы объектов доступны из вашего OptionParser.

### Другие методы

OptionParser поддерживает несколько других открытых методов:

- `set_usage(usage)`

  Устанавливает строку использования в соответствии с правилами, описанными выше для `usage` именованного аргумента конструктора. Передача `None` устанавливает строку использования по умолчанию; используйте `SUPPRESS_USAGE`, чтобы подавить сообщение об использовании.
- `enable_interspersed_args()`, `disable_interspersed_args()`

  Enable/disable positional arguments interspersed with options, similar to GNU getopt (enabled by default). For example, if `"-a"` and `"-b"` are both simple options that take no arguments, `optparse` normally accepts this syntax:

  ```python
  prog -a arg1 -b arg2
  ```

  и обрабатывает его как эквивалент

  ```python
  prog -a -b arg1 arg2
  ```

  Чтобы отключить эту возможность, вызовите `disable_interspersed_args()`. Это восстанавливает традиционный синтаксис Unix, где разбор опций останавливается на первом не-опционном аргументе.
- `set_defaults(dest=value, ...)`

  Устанавливает значения по умолчанию для нескольких назначений опций одновременно. Использование `set_defaults()` – предпочтительный способ задания значений по умолчанию для опций, поскольку несколько опций могут совместно использовать одно назначение. Например, если несколько опций «mode» устанавливают одно и то же назначение, любая из них может задать значение по умолчанию, и побеждает последняя:

  ```python
  parser.add_option("--advanced", action="store_const",
                    dest="mode", const="advanced",
                    default="novice")    # переопределено ниже
  parser.add_option("--novice", action="store_const",
                    dest="mode", const="novice",
                    default="advanced")  # переопределяет вышеуказанную настройку
  ```

  Чтобы избежать этой путаницы, используйте `set_defaults()`:

  ```python
  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` более универсально, но избыточно для многих простых случаев. Часто достаточно простого колбэка.

Определение опции-колбэка состоит из двух шагов:

- определите саму опцию с помощью действия `колбэк`
- написать колбэк – функцию (или метод), которая принимает как минимум четыре аргумента, как описано ниже

### Определение опции-колбэка

As always, the easiest way to define a callback option is by using the `parser.add_option()` method. Apart from `action`, the only option attribute you must specify is `callback`, the function to call:

```python
parser.add_option("-c", action="callback", callback=my_callback)
```

`колбэк` – это функция (или другой вызываемый объект), поэтому вы должны уже определить `my_callback()` до создания этой опции с колбэком. В этом простом случае `optparse` даже не знает, принимает ли [*-c*](https://python-all.ru/3.0/using/cmdline.html#cmdoption-c) какие-то аргументы, что обычно означает, что опция не принимает аргументов – достаточно лишь присутствия [*-c*](https://python-all.ru/3.0/using/cmdline.html#cmdoption-c) в командной строке. Однако в некоторых обстоятельствах колбэк может потреблять произвольное число аргументов командной строки. Вот здесь написание колбэков становится сложным; это рассматривается далее в этом разделе.

`optparse` всегда передаёт вашему колбэку четыре определённых аргумента и передаёт дополнительные, только если они заданы через `callback_args` и `callback_kwargs`. Таким образом, минимальная сигнатура функции колбэка:

```python
def my_callback(option, opt, value, parser):
```

Четыре аргумента колбэка описаны ниже.

Есть ещё несколько атрибутов опции, которые можно указать при определении опции-колбэка:

**[`type`](https://python-all.ru/3.0/library/functions.html#type)**

имеет обычное значение: как и для действий

`store`

или

`append`

, он предписывает

`optparse`

потребить один аргумент и преобразовать его в

[`type`](https://python-all.ru/3.0/library/functions.html#type)

. Однако, вместо сохранения преобразованного значения где-либо,

`optparse`

передаёт его вашей функции колбэка.

**`nargs`**

также имеет обычное значение: если указано и \> 1,

`optparse`

потребит

`nargs`

аргументов, каждый из которых должен быть преобразуем в

[`type`](https://python-all.ru/3.0/library/functions.html#type)

. Затем он передаёт кортеж преобразованных значений вашему колбэку.

**`callback_args`**

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

**`callback_kwargs`**

словарь дополнительных именованных аргументов, передаваемых колбэку

### Как вызываются колбэки

Все колбэки вызываются следующим образом:

```python
func(option, opt_str, value, parser, *args, **kwargs)
```

где

**`option`**

это экземпляр Option, который вызывает колбэк

**`opt_str`**

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

`opt_str`

будет полной, канонической строкой опции – например, если пользователь вводит

`"--foo"`

в командной строке как сокращение для

`"--foobar"`

, то

`opt_str`

будет

`"--foobar"`

.)

**`value`**

это аргумент этой опции, видимый в командной строке.

`optparse`

будет ожидать аргумент, только если задан

[`type`](https://python-all.ru/3.0/library/functions.html#type)

; тип

`value`

будет соответствовать типу, указанному в опции. Если

[`type`](https://python-all.ru/3.0/library/functions.html#type)

для этой опции равен

`None`

(аргумент не ожидается), то

`value`

будет

`None`

. Если

`nargs`

\> 1,

`value`

будет кортежем значений соответствующего типа.

**`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: тривиальный колбэк

Вот пример опции-колбэка, которая не принимает аргументов и просто записывает факт своего появления:

```python
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"` в командной строке.

```python
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"` уже встречалась), потребуется доработка: сообщение об ошибке и устанавливаемый флаг необходимо обобщить.

```python
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: проверка произвольного условия

Конечно, можно задать любое условие – вы не ограничены проверкой значений уже определённых параметров. Например, если есть параметры, которые не должны вызываться в полнолуние, достаточно сделать так:

```python
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`](https://python-all.ru/3.0/library/functions.html#type), то опция принимает один аргумент, который должен быть преобразуем к этому типу; если дополнительно задать `nargs`, то опция принимает `nargs` аргументов.

Вот пример, который просто эмулирует стандартное действие `store`:

```python
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` обычно обрабатывает автоматически. В частности, колбэки должны реализовывать стандартные правила для аргументов `"--"` и `"-"`:

- как `"--"`, так и `"-"` могут быть аргументами параметра
- голый `"--"` (если не является аргументом какого-либо параметра): остановить обработку командной строки и отбросить `"--"`
- голый `"-"` (если не является аргументом какой-либо опции): остановить обработку командной строки, но сохранить `"-"` (добавить его в `parser.largs`)

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

Тем не менее, вот пример попытки создать колбэк для параметра с переменным числом аргументов:

```python
 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:
         # останавливаться на опциях вида --foo
         if arg[:2] == "--" and len(arg) > 2:
             break
         # останавливаться на -a, но не на -3 или -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` интерпретирует опции командной строки, являются действие и тип каждой опции, наиболее вероятное направление расширения – добавление новых действий и новых типов.

### Добавление новых типов

Чтобы добавить новые типы, нужно определить собственный подкласс класса Option из `optparse`. У этого класса есть несколько атрибутов, определяющих типы `optparse`: `TYPES` и `TYPE_CHECKER`.

`TYPES` – это кортеж имен типов; в своем подклассе просто определите новый кортеж `TYPES`, который расширяет стандартный.

`TYPE_CHECKER` – это словарь, сопоставляющий имена типов с функциями проверки типа. Функция проверки типа имеет следующую сигнатуру:

```python
def check_mytype(option, opt, value)
```

где `option` – это экземпляр `Option`, `opt` – строка опции (например, `"-f"`), а `value` – строка из командной строки, которую нужно проверить и преобразовать к нужному типу. `check_mytype()` должна возвращать объект гипотетического типа `mytype`. Значение, возвращаемое функцией проверки типа, в итоге оказывается в экземпляре OptionValues, возвращаемом `OptionParser.parse_args()`, или передается колбэку как параметр `value`.

Функция проверки типа должна возбуждать `OptionValueError` при возникновении каких-либо проблем. `OptionValueError` принимает один строковый аргумент, который передается как есть методу `OptionParser`.`error()`; тот, в свою очередь, добавляет имя программы и строку `"error:"`, выводит все в stderr и завершает процесс.

Вот глупый пример, демонстрирующий добавление типа опции `complex` для разбора комплексных чисел в стиле Python из командной строки. (Это еще более глупо, чем раньше, потому что `optparse` 1.3 добавил встроенную поддержку комплексных чисел, но не будем об этом.)

Сначала необходимые импорты:

```python
from copy import copy
from optparse import Option, OptionValueError
```

Сначала нужно определить проверку типа, так как на нее есть ссылка позже (в атрибуте класса `TYPE_CHECKER` вашего подкласса Option):

```python
def check_complex(option, opt, value):
    try:
        return complex(value)
    except ValueError:
        raise OptionValueError(
            "option %s: invalid complex value: %r" % (opt, value))
```

Наконец, подкласс Option:

```python
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:

```python
parser = OptionParser(option_class=MyOption)
parser.add_option("-c", type="complex")
```

В качестве альтернативы можно составить собственный список опций и передать его OptionParser; если не использовать `add_option()` указанным выше способом, не нужно сообщать OptionParser, какой класс опций использовать:

```python
option_list = [MyOption("-c", action="store", type="complex", dest="c")]
parser = OptionParser(option_list=option_list)
```

### Добавление новых действий

Добавление новых действий немного сложнее, потому что нужно понимать, что у `optparse` есть несколько классификаций действий:

**«store»-действия**

действия, в результате которых

`optparse`

сохраняет значение в атрибут текущего экземпляра OptionValues; для таких опций требуется атрибут

`dest`

, передаваемый конструктору Option

**«typed»-действия**

действия, которые берут значение из командной строки и ожидают, что оно будет определенного типа; точнее, строка, которую можно преобразовать к определенному типу. Для таких опций требуется атрибут

[`type`](https://python-all.ru/3.0/library/functions.html#type)

конструктора Option.

Это пересекающиеся множества: некоторые стандартные действия «store»: `store`, `store_const`, `append` и `count`, а стандартные действия «typed»: `store`, `append` и `колбэк`.

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

**`ACTIONS`**

все действия должны быть перечислены в ACTIONS

**`STORE_ACTIONS`**

«store»-действия дополнительно перечислены здесь

**`TYPED_ACTIONS`**

«typed»-действия дополнительно перечислены здесь

**`ALWAYS_TYPED_ACTIONS`**

действия, которые всегда используют тип (т.е. их опции всегда принимают значение), дополнительно перечислены здесь. Единственный эффект этого заключается в том, что

`optparse`

назначает тип по умолчанию,

`string`

, опциям без явного типа, чье действие перечислено в

`ALWAYS_TYPED_ACTIONS`

.

Чтобы реализовать новое действие, необходимо переопределить метод Option `take_action()` и добавить ветвь, распознающую это действие.

Например, давайте добавим действие `extend`. Оно похоже на стандартное действие `append`, но вместо того, чтобы взять одно значение из командной строки и добавить его в существующий список, `extend` возьмет несколько значений в одной строке, разделенной запятыми, и расширит существующий список этими значениями. То есть, если `"--names"` – это опция `extend` типа `string`, то командная строка

```python
--names=foo,bar --names blah --names ding,dong
```

приведёт к списку

```python
["foo", "bar", "blah", "ding", "dong"]
```

Снова определим подкласс Option:

```python
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()`](https://python-all.ru/3.0/library/functions.html#getattr) с предохранительным клапаном; он вызывается как

  ```python
  values.ensure_value(attr, value)
  ```

  Если атрибут `attr` объекта `values` не существует или равен None, то ensure\_value() сначала устанавливает его в `value`, а затем возвращает значение. Это очень удобно для таких действий, как `extend`, `append` и `count`, все они накапливают данные в переменной и ожидают, что эта переменная будет определенного типа (список для первых двух, целое число для последнего). Использование `ensure_value()` означает, что сценарии, использующие ваше действие, могут не беспокоиться о задании значения по умолчанию для соответствующих опций; они могут просто оставить значение по умолчанию None, и `ensure_value()` позаботится о правильной установке, когда это потребуется.
