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

---

# Руководство по Argparse

**автор**

Tshepang Lekhonkhobe

Это руководство предназначено для плавного введения в [`argparse`](https://python-all.ru/2.7/library/argparse.html#module-argparse), рекомендованный модуль разбора командной строки в стандартной библиотеке Python. Оно было написано для argparse в Python 3. Некоторые детали отличаются в 2.x, особенно некоторые сообщения об исключениях, которые были улучшены в 3.x.

> **Примечание**
>
> Существуют ещё два модуля, выполняющие ту же задачу, а именно [`getopt`](https://python-all.ru/2.7/library/getopt.html#module-getopt) (аналог `getopt()` из языка C ) и устаревший [`optparse`](https://python-all.ru/2.7/library/optparse.html#module-optparse). Обратите также внимание, что [`argparse`](https://python-all.ru/2.7/library/argparse.html#module-argparse) основан на [`optparse`](https://python-all.ru/2.7/library/optparse.html#module-optparse), и поэтому очень похож по использованию.

## Основные понятия

Давайте покажем, какие возможности мы будем изучать в этом вводном руководстве, на примере команды **ls**:

```sh
$ ls
cpython  devguide  prog.py  pypy  rm-unused-function.patch
$ ls pypy
ctypes_configure  demo  dotviewer  include  lib_pypy  lib-python ...
$ ls -l
total 20
drwxr-xr-x 19 wena wena 4096 Feb 18 18:51 cpython
drwxr-xr-x  4 wena wena 4096 Feb  8 12:04 devguide
-rwxr-xr-x  1 wena wena  535 Feb 19 00:05 prog.py
drwxr-xr-x 14 wena wena 4096 Feb  7 00:59 pypy
-rw-r--r--  1 wena wena  741 Feb 18 01:01 rm-unused-function.patch
$ ls --help
Usage: ls [OPTION]... [FILE]...
List information about the FILEs (the current directory by default).
Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.
...
```

Из этих четырёх команд можно извлечь несколько понятий:

- Команда **ls** полезна при запуске без каких-либо опций. По умолчанию она выводит содержимое текущего каталога.
- Если нужно больше, чем даётся по умолчанию, мы сообщаем программе дополнительные сведения. В данном случае мы хотим показать другой каталог – `pypy`. Мы указали так называемый позиционный аргумент. Он назван так потому, что программа понимает, что делать со значением, только по его позиции в командной строке. Это понятие лучше видно на примере команды **cp**, простейшее использование которой – `cp SRC DEST`. Первая позиция – *что нужно скопировать*, а вторая – *куда скопировать*.
- Теперь представим, что мы хотим изменить поведение программы. В нашем примере мы выводим больше информации о каждом файле, а не только имена. `-l` в этом случае называется необязательным аргументом.
- Это фрагмент справки. Она очень полезна: вы можете встретить незнакомую программу и понять, как она работает, просто прочитав её справку.

## Основы

Начнём с очень простого примера, который (почти) ничего не делает:

```python
import argparse
parser = argparse.ArgumentParser()
parser.parse_args()
```

Ниже приведён результат выполнения кода:

```sh
$ python prog.py
$ python prog.py --help
usage: prog.py [-h]

optional arguments:
  -h, --help  show this help message and exit
$ python prog.py --verbose
usage: prog.py [-h]
prog.py: error: unrecognized arguments: --verbose
$ python prog.py foo
usage: prog.py [-h]
prog.py: error: unrecognized arguments: foo
```

Вот что происходит:

- Запуск скрипта без опций не выводит ничего в stdout. Не очень полезно.
- Второй запуск начинает показывать полезность модуля [`argparse`](https://python-all.ru/2.7/library/argparse.html#module-argparse). Мы почти ничего не сделали, но уже получили хорошее сообщение справки.
- Опция `--help`, которую можно сократить до `-h`, – единственная опция, которую мы получаем бесплатно (т.е. её не нужно указывать). Всё остальное приводит к ошибке. Но даже в этом случае мы получаем полезное сообщение об использовании – тоже бесплатно.

## Знакомство с позиционными аргументами

Пример:

```python
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("echo")
args = parser.parse_args()
print args.echo
```

И запуск кода:

```sh
$ python prog.py
usage: prog.py [-h] echo
prog.py: error: the following arguments are required: echo
$ python prog.py --help
usage: prog.py [-h] echo

positional arguments:
  echo

optional arguments:
  -h, --help  show this help message and exit
$ python prog.py foo
foo
```

Вот что происходит:

- Мы добавили метод `add_argument()`, который используется для указания опций командной строки, которые программа готова принять. В данном случае я назвал его `echo`, чтобы оно соответствовало своей функции.
- Теперь для вызова программы требуется указать опцию.
- Метод `parse_args()` на самом деле возвращает некоторые данные из указанных опций, в данном случае `echo`.
- Переменная – это своего рода «магия», которую [`argparse`](https://python-all.ru/2.7/library/argparse.html#module-argparse) выполняет бесплатно (т.е. не нужно указывать, в какой переменной хранится это значение). Вы также заметите, что её имя совпадает со строковым аргументом, переданным методу – `echo`.

Однако обратите внимание, что, хотя справка выглядит красиво, пока она не так полезна, как могла бы быть. Например, мы видим, что у нас есть позиционный аргумент `echo`, но не знаем, что он делает – только догадываемся или читаем исходный код. Давайте сделаем его немного полезнее:

```python
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("echo", help="echo the string you use here")
args = parser.parse_args()
print args.echo
```

И получаем:

```sh
$ python prog.py -h
usage: prog.py [-h] echo

positional arguments:
  echo        echo the string you use here

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

А теперь давайте сделаем что-нибудь ещё более полезное:

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

Ниже приведён результат выполнения кода:

```sh
$ python prog.py 4
Traceback (most recent call last):
  File "prog.py", line 5, in <module>
    print args.square**2
TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
```

Всё пошло не так. Это потому, что [`argparse`](https://python-all.ru/2.7/library/argparse.html#module-argparse) воспринимает переданные ему параметры как строки, если не указать иное. Итак, укажем [`argparse`](https://python-all.ru/2.7/library/argparse.html#module-argparse) воспринимать ввод как целое число:

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

Ниже приведён результат выполнения кода:

```sh
$ python prog.py 4
16
$ python prog.py four
usage: prog.py [-h] square
prog.py: error: argument square: invalid int value: 'four'
```

Всё прошло хорошо. Программа теперь даже корректно завершается при неверном вводе перед продолжением.

## Знакомство с необязательными аргументами

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

```python
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--verbosity", help="increase output verbosity")
args = parser.parse_args()
if args.verbosity:
    print "verbosity turned on"
```

И вывод:

```sh
$ python prog.py --verbosity 1
verbosity turned on
$ python prog.py
$ python prog.py --help
usage: prog.py [-h] [--verbosity VERBOSITY]

optional arguments:
  -h, --help            show this help message and exit
  --verbosity VERBOSITY
                        increase output verbosity
$ python prog.py --verbosity
usage: prog.py [-h] [--verbosity VERBOSITY]
prog.py: error: argument --verbosity: expected one argument
```

Вот что происходит:

- Программа написана так, чтобы выводить что-то, когда указан `--verbosity`, и ничего не выводить, если не указан.
- Чтобы показать, что опция действительно необязательна, при запуске программы без неё ошибки не возникает. Обратите внимание: по умолчанию, если необязательный аргумент не указан, соответствующая переменная (в данном случае `args.verbosity`) получает значение `None`, из-за чего она не проходит проверку на истинность в операторе [`if`](https://python-all.ru/2.7/reference/compound_stmts.html#if).
- Справочное сообщение немного отличается.
- При использовании опции `--verbosity` необходимо также указать некоторое значение, любое значение.

В приведённом выше примере `--verbosity` принимает любые целые числа, но для нашей простой программы на самом деле полезны только два значения: `True` или `False`. Давайте соответствующим образом изменим код:

```python
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--verbose", help="increase output verbosity",
                    action="store_true")
args = parser.parse_args()
if args.verbose:
   print "verbosity turned on"
```

И вывод:

```sh
$ python prog.py --verbose
verbosity turned on
$ python prog.py --verbose 1
usage: prog.py [-h] [--verbose]
prog.py: error: unrecognized arguments: 1
$ python prog.py --help
usage: prog.py [-h] [--verbose]

optional arguments:
  -h, --help  show this help message and exit
  --verbose   increase output verbosity
```

Вот что происходит:

- Теперь опция больше напоминает флаг, нежели что-то, требующее значения. Мы даже изменили имя опции в соответствии с этой идеей. Обратите внимание: теперь мы указываем новый ключевой аргумент `action` и присваиваем ему значение `"store_true"`. Это означает, что если опция указана, то `args.verbose` присваивается значение `True`. Если не указана – то `False`.
- Программа выдаёт ошибку, если указано значение, в полном соответствии с тем, что такое флаги на самом деле.
- Обратите внимание на другой текст справки.

### Короткие опции

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

```python
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-v", "--verbose", help="increase output verbosity",
                    action="store_true")
args = parser.parse_args()
if args.verbose:
    print "verbosity turned on"
```

И вот:

```sh
$ python prog.py -v
verbosity turned on
$ python prog.py --help
usage: prog.py [-h] [-v]

optional arguments:
  -h, --help     show this help message and exit
  -v, --verbose  increase output verbosity
```

Обратите внимание, что новая возможность также отражена в справочном тексте.

## Сочетание позиционных и необязательных аргументов

Наша программа становится всё сложнее:

```python
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
                    help="display a square of a given number")
parser.add_argument("-v", "--verbose", action="store_true",
                    help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbose:
    print "the square of {} equals {}".format(args.square, answer)
else:
    print answer
```

А теперь вывод:

```sh
$ python prog.py
usage: prog.py [-h] [-v] square
prog.py: error: the following arguments are required: square
$ python prog.py 4
16
$ python prog.py 4 --verbose
the square of 4 equals 16
$ python prog.py --verbose 4
the square of 4 equals 16
```

- Мы вернули позиционный аргумент, отсюда и жалоба.
- Обратите внимание: порядок не важен.

А что, если вернуть нашей программе возможность иметь несколько значений уровня подробности вывода и на самом деле их использовать:

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

И вывод:

```sh
$ python prog.py 4
16
$ python prog.py 4 -v
usage: prog.py [-h] [-v VERBOSITY] square
prog.py: error: argument -v/--verbosity: expected one argument
$ python prog.py 4 -v 1
4^2 == 16
$ python prog.py 4 -v 2
the square of 4 equals 16
$ python prog.py 4 -v 3
16
```

Все они выглядят хорошо, кроме последнего, который выявляет ошибку в нашей программе. Давайте исправим её, ограничив значения, которые может принимать опция `--verbosity`:

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

И вывод:

```sh
$ python prog.py 4 -v 3
usage: prog.py [-h] [-v {0,1,2}] square
prog.py: error: argument -v/--verbosity: invalid choice: 3 (choose from 0, 1, 2)
$ python prog.py 4 -h
usage: prog.py [-h] [-v {0,1,2}] square

positional arguments:
  square                display a square of a given number

optional arguments:
  -h, --help            show this help message and exit
  -v {0,1,2}, --verbosity {0,1,2}
                        increase output verbosity
```

Обратите внимание: изменение также отражается как в сообщении об ошибке, так и в строке справки.

Теперь давайте применим другой подход к работе с подробностью вывода, который довольно распространён. Он также соответствует тому, как исполняемый файл CPython обрабатывает собственный аргумент подробности (проверьте вывод `python --help`):

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

Введено ещё одно действие – “count”, для подсчёта количества вхождений определённых необязательных аргументов:

```sh
$ python prog.py 4
16
$ python prog.py 4 -v
4^2 == 16
$ python prog.py 4 -vv
the square of 4 equals 16
$ python prog.py 4 --verbosity --verbosity
the square of 4 equals 16
$ python prog.py 4 -v 1
usage: prog.py [-h] [-v] square
prog.py: error: unrecognized arguments: 1
$ python prog.py 4 -h
usage: prog.py [-h] [-v] square

positional arguments:
  square           display a square of a given number

optional arguments:
  -h, --help       show this help message and exit
  -v, --verbosity  increase output verbosity
$ python prog.py 4 -vvv
16
```

- Да, теперь это больше похоже на флаг (аналогично `action="store_true"` в предыдущей версии нашего скрипта). Этим и объясняется жалоба.
- Кроме того, оно ведёт себя аналогично действию «store\_true».
- А вот демонстрация того, что даёт действие «count». Вы, вероятно, уже встречали подобное использование.
- И, как и в случае с действием “store\_true”, если не указать флаг `-v`, считается, что этот флаг имеет значение `None`.
- Как и следовало ожидать, при указании длинной формы флага мы получим тот же результат.
- К сожалению, наш вывод справки не очень информативен о новых возможностях скрипта, но это всегда можно исправить, улучшив документацию (например, через именованный аргумент `help`).
- Последний вывод обнаруживает ошибку в нашей программе.

Исправим:

```python
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
                    help="display a square of a given number")
parser.add_argument("-v", "--verbosity", action="count",
                    help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2

# исправление ошибки: заменить == на >=
if args.verbosity >= 2:
    print "the square of {} equals {}".format(args.square, answer)
elif args.verbosity >= 1:
    print "{}^2 == {}".format(args.square, answer)
else:
    print answer
```

И вот что получается:

```sh
$ python prog.py 4 -vvv
the square of 4 equals 16
$ python prog.py 4 -vvvv
the square of 4 equals 16
$ python prog.py 4
Traceback (most recent call last):
  File "prog.py", line 11, in <module>
    if args.verbosity >= 2:
TypeError: unorderable types: NoneType() >= int()
```

- Первый вывод прошёл хорошо и исправляет предыдущую ошибку. То есть мы хотим, чтобы любое значение \>= 2 давало максимально подробный вывод.
- Третий вывод уже не так хорош.

Исправим и эту ошибку:

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

Мы только что ввели ещё один именованный аргумент – `default`. Мы установили его в `0`, чтобы можно было сравнивать с другими целочисленными значениями. Помните: по умолчанию, если необязательный аргумент не указан, он получает значение `None`, и такое значение нельзя сравнить с целым числом (отсюда исключение [`TypeError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.TypeError)).

И:

```sh
$ python prog.py 4
16
```

Уже с тем, что мы узнали, можно уйти довольно далеко, а мы только коснулись поверхности. Модуль [`argparse`](https://python-all.ru/2.7/library/argparse.html#module-argparse) очень мощный, и мы рассмотрим его чуть подробнее, прежде чем завершить этот учебник.

## Немного более продвинутый материал

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

```python
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("x", type=int, help="the base")
parser.add_argument("y", type=int, help="the exponent")
parser.add_argument("-v", "--verbosity", action="count", default=0)
args = parser.parse_args()
answer = args.x**args.y
if args.verbosity >= 2:
    print "{} to the power {} equals {}".format(args.x, args.y, answer)
elif args.verbosity >= 1:
    print "{}^{} == {}".format(args.x, args.y, answer)
else:
    print answer
```

Вывод:

```sh
$ python prog.py
usage: prog.py [-h] [-v] x y
prog.py: error: the following arguments are required: x, y
$ python prog.py -h
usage: prog.py [-h] [-v] x y

positional arguments:
  x                the base
  y                the exponent

optional arguments:
  -h, --help       show this help message and exit
  -v, --verbosity
$ python prog.py 4 2 -v
4^2 == 16
```

Обратите внимание: до сих пор мы использовали уровень подробности, чтобы *изменять* выводимый текст. В следующем примере уровень подробности используется, чтобы выводить *больше* текста:

```python
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("x", type=int, help="the base")
parser.add_argument("y", type=int, help="the exponent")
parser.add_argument("-v", "--verbosity", action="count", default=0)
args = parser.parse_args()
answer = args.x**args.y
if args.verbosity >= 2:
    print "Running '{}'".format(__file__)
if args.verbosity >= 1:
    print "{}^{} ==".format(args.x, args.y),
print answer
```

Вывод:

```sh
$ python prog.py 4 2
16
$ python prog.py 4 2 -v
4^2 == 16
$ python prog.py 4 2 -vv
Running 'prog.py'
4^2 == 16
```

### Конфликтующие опции

До сих пор мы работали с двумя методами экземпляра [`argparse.ArgumentParser`](https://python-all.ru/2.7/library/argparse.html#argparse.ArgumentParser). Познакомимся с третьим – `add_mutually_exclusive_group()`. Он позволяет указывать опции, которые противоречат друг другу. Давайте также изменим остальную часть программы, чтобы новая функциональность стала более осмысленной: мы введём опцию `--quiet`, которая будет противоположностью опции `--verbose`:

```python
import argparse

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("-v", "--verbose", action="store_true")
group.add_argument("-q", "--quiet", action="store_true")
parser.add_argument("x", type=int, help="the base")
parser.add_argument("y", type=int, help="the exponent")
args = parser.parse_args()
answer = args.x**args.y

if args.quiet:
    print answer
elif args.verbose:
    print "{} to the power {} equals {}".format(args.x, args.y, answer)
else:
    print "{}^{} == {}".format(args.x, args.y, answer)
```

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

```sh
$ python prog.py 4 2
4^2 == 16
$ python prog.py 4 2 -q
16
$ python prog.py 4 2 -v
4 to the power 2 equals 16
$ python prog.py 4 2 -vq
usage: prog.py [-h] [-v | -q] x y
prog.py: error: argument -q/--quiet: not allowed with argument -v/--verbose
$ python prog.py 4 2 -v --quiet
usage: prog.py [-h] [-v | -q] x y
prog.py: error: argument -q/--quiet: not allowed with argument -v/--verbose
```

Это должно быть легко понять. Я добавил последний вывод, чтобы вы могли увидеть, какую гибкость это даёт: например, смешивание длинной и короткой форм опций.

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

```python
import argparse

parser = argparse.ArgumentParser(description="calculate X to the power of Y")
group = parser.add_mutually_exclusive_group()
group.add_argument("-v", "--verbose", action="store_true")
group.add_argument("-q", "--quiet", action="store_true")
parser.add_argument("x", type=int, help="the base")
parser.add_argument("y", type=int, help="the exponent")
args = parser.parse_args()
answer = args.x**args.y

if args.quiet:
    print answer
elif args.verbose:
    print "{} to the power {} equals {}".format(args.x, args.y, answer)
else:
    print "{}^{} == {}".format(args.x, args.y, answer)
```

Обратите внимание на небольшое различие в тексте использования. Обратите внимание на `[-v | -q]`, который сообщает, что мы можем использовать либо `-v`, либо `-q`, но не оба одновременно:

```sh
$ python prog.py --help
usage: prog.py [-h] [-v | -q] x y

calculate X to the power of Y

positional arguments:
  x              the base
  y              the exponent

optional arguments:
  -h, --help     show this help message and exit
  -v, --verbose
  -q, --quiet
```

## Заключение

Модуль [`argparse`](https://python-all.ru/2.7/library/argparse.html#module-argparse) предлагает гораздо больше, чем показано здесь. Его документация весьма подробна и обстоятельна, полна примеров. Пройдя этот учебник, вы легко сможете её усвоить, не чувствуя перегрузки.
