Руководство по argparse
- автор:
-
Tshepang Mbambo
Это руководство призвано познакомить вас с argparse — рекомендуемым модулем стандартной библиотеки Python для разбора аргументов командной строки.
Примечание
Стандартная библиотека включает ещё две библиотеки, непосредственно связанные с обработкой параметров командной строки: модуль более низкого уровня optparse (для настройки которого под конкретное приложение может потребоваться больше кода, но который также позволяет приложению запрашивать варианты поведения, не поддерживаемые argparse), и модуль очень низкого уровня getopt (предназначенный специально в качестве аналога семейства функций getopt(), доступных программистам на C). Хотя в этом руководстве мы не рассматриваем эти модули напрямую, многие основные концепции в argparse впервые появились в optparse, поэтому некоторые аспекты этого руководства будут полезны и пользователям optparse.
Основные понятия
Рассмотрим функциональность, которую мы изучим в этом вводном руководстве, на примере команды ls:
$ 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называется необязательным аргументом. - Это фрагмент справочного текста. Он очень полезен: встретив программу, которой вы раньше не пользовались, можно понять, как она работает, просто прочитав справку.
Основы
Начнём с очень простого примера, который (почти) ничего не делает:
import argparse parser = argparse.ArgumentParser() parser.parse_args()
Результат выполнения этого кода:
$ python prog.py $ python prog.py --help usage: prog.py [-h] options: -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. Мы почти ничего не сделали, но уже получили удобное справочное сообщение. - Параметр
--help, который также можно записать сокращённо как-h, — единственный параметр, доступный нам бесплатно (то есть его не нужно задавать). Указание любого другого параметра приводит к ошибке. Но даже в этом случае мы бесплатно получаем полезное сообщение об использовании.
Знакомство с позиционными аргументами
Пример:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("echo")
args = parser.parse_args()
print(args.echo)
Запустим код:
$ 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 options: -h, --help show this help message and exit $ python prog.py foo foo
Вот что происходит:
- Мы добавили метод
add_argument(), с помощью которого задаём параметры командной строки, принимаемые программой. В данном случае я назвал параметрecho, чтобы его имя соответствовало назначению. - Теперь для вызова нашей программы нужно указать аргумент.
- Метод
parse_args()возвращает данные из указанных параметров — в данном случаеecho. - Переменная появляется как бы «по волшебству»: это
argparseделает за нас бесплатно (то есть нам не нужно указывать, в какую переменную сохраняется это значение). Обратите внимание, что её имя совпадает со строковым аргументом, переданным методу:echo.
Однако, несмотря на то что справка выглядит хорошо, сейчас она не настолько полезна, насколько могла бы быть. Например, мы видим, что получили позиционный аргумент echo, но не знаем, что он делает, если не догадаемся сами или не прочитаем исходный код. Давайте сделаем справку немного полезнее:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("echo", help="echo the string you use here")
args = parser.parse_args()
print(args.echo)
Получаем:
$ python prog.py -h usage: prog.py [-h] echo positional arguments: echo echo the string you use here options: -h, --help show this help message and exit
А теперь попробуем сделать кое-что ещё полезнее:
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)
Результат выполнения этого кода:
$ 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 считает переданные ему параметры строками, если не указать иное. Поэтому сообщим argparse, что нужно обрабатывать эти данные как целое число:
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)
Результат выполнения этого кода:
$ python prog.py 4 16 $ python prog.py four usage: prog.py [-h] square prog.py: error: argument square: invalid int value: 'four'
Теперь всё работает как надо. Программа даже предусмотрительно завершается при некорректном вводе, не приступая к дальнейшему выполнению.
Знакомство с необязательными аргументами
До сих пор мы работали с позиционными аргументами. Посмотрим, как добавлять необязательные:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--verbosity", help="increase output verbosity")
args = parser.parse_args()
if args.verbosity:
print("verbosity turned on")
Результат:
$ python prog.py --verbosity 1
verbosity turned on
$ python prog.py
$ python prog.py --help
usage: prog.py [-h] [--verbosity VERBOSITY]
options:
-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завершается неудачей. - Справочное сообщение немного изменилось.
- При использовании параметра
--verbosityнужно также указать какое-либо значение.
Пример выше принимает произвольные целые значения для --verbosity, но для нашей простой программы полезны только два значения: True и False. Изменим код соответствующим образом:
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")
Результат:
$ 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] options: -h, --help show this help message and exit --verbose increase output verbosity
Вот что происходит:
- Теперь этот параметр скорее флаг, чем параметр, которому нужно передать значение. Мы даже изменили его имя, чтобы подчеркнуть эту идею. Обратите внимание на новое ключевое слово
action, которому мы присваиваем значение"store_true". Это значит, что при указании параметра переменнойargs.verboseприсваивается значениеTrue. Если параметр не указан, подразумевается значениеFalse. - При указании значения возникает ошибка — именно так и должны вести себя флаги.
- Обратите внимание на изменившийся текст справки.
Короткие параметры
Если вы знакомы с командной строкой, то, возможно, заметили, что мы ещё не говорили о коротких формах параметров. Это довольно просто:
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")
Вот результат:
$ python prog.py -v verbosity turned on $ python prog.py --help usage: prog.py [-h] [-v] options: -h, --help show this help message and exit -v, --verbose increase output verbosity
Обратите внимание, что новая возможность также отражена в справке.
Сочетание позиционных и необязательных аргументов
Наша программа становится всё сложнее:
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(f"the square of {args.square} equals {answer}")
else:
print(answer)
А теперь результат:
$ 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
- Мы вернули позиционный аргумент, поэтому возникла ошибка.
- Обратите внимание, что порядок не имеет значения.
Вернём нашей программе возможность принимать несколько значений уровня подробности и научим её использовать их:
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(f"the square of {args.square} equals {answer}")
elif args.verbosity == 1:
print(f"{args.square}^2 == {answer}")
else:
print(answer)
Результат:
$ 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:
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(f"the square of {args.square} equals {answer}")
elif args.verbosity == 1:
print(f"{args.square}^2 == {answer}")
else:
print(answer)
Результат:
$ 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
options:
-h, --help show this help message and exit
-v, --verbosity {0,1,2}
increase output verbosity
Обратите внимание: это изменение отразилось и на сообщении об ошибке, и на справочном тексте.
Теперь рассмотрим другой, довольно распространённый способ управления уровнем подробности. Он также соответствует тому, как исполняемый файл CPython обрабатывает собственный аргумент уровня подробности (проверьте вывод команды python --help):
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(f"the square of {args.square} equals {answer}")
elif args.verbosity == 1:
print(f"{args.square}^2 == {answer}")
else:
print(answer)
Мы добавили ещё одно действие — «count», которое подсчитывает количество указаний определённых параметров.
$ 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 options: -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». Вероятно, вы уже встречали подобное использование.
- Если не указать флаг
-v, его значение будет считаться равнымNone. - Как и следовало ожидать, при указании полной формы флага мы получим тот же результат.
- К сожалению, справка не очень хорошо объясняет новую возможность, появившуюся в нашем скрипте. Это можно исправить, дополнив документацию скрипта (например, с помощью именованного аргумента
help). - Последний результат выявляет ошибку в нашей программе.
Исправим её:
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
# bugfix: replace == with >=
if args.verbosity >= 2:
print(f"the square of {args.square} equals {answer}")
elif args.verbosity >= 1:
print(f"{args.square}^2 == {answer}")
else:
print(answer)
Вот результат:
$ 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: '>=' not supported between instances of 'NoneType' and 'int'
- Первый результат верный и исправляет обнаруженную ранее ошибку. То есть любое значение >= 2 должно обеспечивать максимально подробный вывод.
- Третий результат неудачный.
Исправим эту ошибку:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
help="display a square of a given number")
parser.add_argument("-v", "--verbosity", action="count", default=0,
help="increase output verbosity")
args = parser.parse_args()
answer = args.square**2
if args.verbosity >= 2:
print(f"the square of {args.square} equals {answer}")
elif args.verbosity >= 1:
print(f"{args.square}^2 == {answer}")
else:
print(answer)
Мы добавили ещё одно ключевое слово — default. Мы задали ему значение 0, чтобы его можно было сравнивать с другими целочисленными значениями. Помните, что по умолчанию, если необязательный аргумент не указан, ему присваивается значение None, которое нельзя сравнить с целым числом (отсюда исключение TypeError).
И вот результат:
$ python prog.py 4 16
Изученных нами возможностей уже достаточно, чтобы зайти довольно далеко, но мы лишь слегка коснулись темы. Модуль argparse очень мощный. Прежде чем завершить это руководство, изучим ещё несколько его возможностей.
Чуть более сложные примеры
Что, если мы захотим расширить нашу небольшую программу, чтобы она выполняла не только возведение в квадрат, но и другие операции:
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(f"{args.x} to the power {args.y} equals {answer}")
elif args.verbosity >= 1:
print(f"{args.x}^{args.y} == {answer}")
else:
print(answer)
Результат:
$ 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 options: -h, --help show this help message and exit -v, --verbosity $ python prog.py 4 2 -v 4^2 == 16
До сих пор мы использовали уровень подробности, чтобы изменять выводимый текст. В следующем примере уровень подробности используется, чтобы выводить больше текста:
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(f"Running '{__file__}'")
if args.verbosity >= 1:
print(f"{args.x}^{args.y} == ", end="")
print(answer)
Результат:
$ 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
Указание неоднозначных аргументов
Если неясно, является ли аргумент позиционным или относится к параметру, можно использовать --, чтобы сообщить методу parse_args(), что всё, что следует за ним, является позиционным аргументом:
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-n', nargs='+')
>>> parser.add_argument('args', nargs='*')
>>> # ambiguous, so parse_args assumes it's an option
>>> parser.parse_args(['-f'])
usage: PROG [-h] [-n N [N ...]] [args ...]
PROG: error: unrecognized arguments: -f
>>> parser.parse_args(['--', '-f'])
Namespace(args=['-f'], n=None)
>>> # ambiguous, so the -n option greedily accepts arguments
>>> parser.parse_args(['-n', '1', '2', '3'])
Namespace(args=[], n=['1', '2', '3'])
>>> parser.parse_args(['-n', '1', '--', '2', '3'])
Namespace(args=['2', '3'], n=['1'])
Конфликтующие параметры
До сих пор мы работали с двумя методами экземпляра argparse.ArgumentParser. Познакомимся с третьим — add_mutually_exclusive_group(). Он позволяет задавать взаимно конфликтующие параметры. Заодно изменим остальную часть программы, чтобы новые возможности выглядели логичнее: добавим параметр --quiet, противоположный параметру --verbose:
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(f"{args.x} to the power {args.y} equals {answer}")
else:
print(f"{args.x}^{args.y} == {answer}")
Теперь наша программа стала проще, но ради демонстрации мы отказались от некоторых возможностей. В любом случае, вот результат:
$ 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
Здесь всё должно быть понятно. Последний результат добавлен, чтобы показать гибкость: можно сочетать полные и короткие формы параметров.
Перед тем как закончить, вероятно, стоит сообщить пользователям основное назначение программы — на случай, если они его не знают:
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(f"{args.x} to the power {args.y} equals {answer}")
else:
print(f"{args.x}^{args.y} == {answer}")
Обратите внимание на небольшое изменение текста использования. Также обратите внимание на [-v | -q]: оно сообщает, что можно использовать либо -v, либо -q, но не оба параметра одновременно:
$ 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 options: -h, --help show this help message and exit -v, --verbose -q, --quiet
Как перевести вывод argparse
Вывод модуля argparse, включая справочный текст и сообщения об ошибках, можно переводить с помощью модуля gettext. Благодаря этому приложения могут легко локализовать сообщения, создаваемые модулем argparse. См. также раздел Интернационализация программ и модулей.
Например, в этом выводе argparse:
$ 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 options: -h, --help show this help message and exit -v, --verbose -q, --quiet
Все строки usage:, positional arguments:, options: и show this help message and exit можно переводить.
Чтобы перевести эти строки, сначала нужно извлечь их в файл .po. Например, с помощью Babel выполните эту команду:
$ pybabel extract -o messages.po /usr/lib/python3.12/argparse.py
Эта команда извлечёт все переводимые строки из модуля argparse и запишет их в файл с именем messages.po. Предполагается, что Python установлен в /usr/lib.
Узнать расположение модуля argparse в вашей системе можно с помощью этого скрипта:
import argparse print(argparse.__file__)
После того как сообщения в файле .po будут переведены, а переводы установлены с помощью gettext, модуль argparse сможет выводить переведённые сообщения.
Чтобы переводить собственные строки в выводе argparse, используйте gettext.
Преобразователи пользовательских типов
Модуль argparse позволяет задавать пользовательские преобразователи типов для аргументов командной строки. С их помощью можно изменять пользовательский ввод до его сохранения в argparse.Namespace. Это полезно, когда необходимо предварительно обработать данные перед использованием в программе.
Для пользовательского преобразователя типа можно использовать любой вызываемый объект, который принимает один строковый аргумент (значение аргумента) и возвращает преобразованное значение. Если же нужно обрабатывать более сложные сценарии, вместо этого можно использовать пользовательский класс действия с параметром action.
Например, предположим, что нужно обрабатывать аргументы с разными префиксами и соответствующим образом преобразовывать их:
import argparse
parser = argparse.ArgumentParser(prefix_chars='-+')
parser.add_argument('-a', metavar='<value>', action='append',
type=lambda x: ('-', x))
parser.add_argument('+a', metavar='<value>', action='append',
type=lambda x: ('+', x))
args = parser.parse_args()
print(args)
Результат:
$ python prog.py -a value1 +a value2
Namespace(a=[('-', 'value1'), ('+', 'value2')])
В этом примере мы:
- Создали анализатор с пользовательскими символами префиксов, используя параметр
prefix_chars. - Определили два аргумента —
-aи+a, — для которых использовали параметрtype, чтобы создать пользовательские преобразователи типов, сохраняющие значение вместе с префиксом в кортеже.
Без пользовательских преобразователей типов аргументы -a и +a считались бы одним и тем же аргументом, что было бы нежелательно. Пользовательские преобразователи типов позволили нам различать эти два аргумента.
Заключение
Модуль argparse предлагает гораздо больше возможностей, чем рассмотрено здесь. Его документация подробна и обстоятельна, в ней много примеров. Пройдя это руководство, вы сможете без труда разобраться в ней, не чувствуя себя перегруженными.
© 2001–2025 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/howto/argparse.html