Підручник Argparse¶
- автор
Tshepang Lekhonkhobe
Цей підручник призначений для ознайомлення з argparse
, рекомендованим модулем аналізу командного рядка в стандартній бібліотеці Python.
Примітка
There are two other modules that fulfill the same task, namely
getopt
(an equivalent for getopt()
from the C
language) and the deprecated optparse
.
Note also that argparse
is based on optparse
,
and therefore very similar in terms of usage.
Концепції¶
Давайте покажемо тип функціональності, який ми збираємося досліджувати в цьому вступному посібнику, використовуючи команду 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()
Нижче наведено результат виконання коду:
$ python3 prog.py
$ python3 prog.py --help
usage: prog.py [-h]
optional arguments:
-h, --help show this help message and exit
$ python3 prog.py --verbose
usage: prog.py [-h]
prog.py: error: unrecognized arguments: --verbose
$ python3 prog.py foo
usage: prog.py [-h]
prog.py: error: unrecognized arguments: foo
Ось що відбувається:
Запуск сценарію без будь-яких параметрів призводить до того, що стандартний вивід нічого не відображає. Не дуже корисно.
Другий починає відображати корисність модуля
argparse
. Ми майже нічого не зробили, але вже отримуємо гарне довідкове повідомлення.Опція
--help
, яку також можна скоротити до-h
, є єдиною опцією, яку ми отримуємо безкоштовно (тобто її не потрібно вказувати). Вказівка будь-чого іншого призводить до помилки. Але навіть тоді ми отримуємо корисне повідомлення про використання, також безкоштовно.
Представлення позиційних аргументів¶
Приклад:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("echo")
args = parser.parse_args()
print(args.echo)
І запуск коду:
$ python3 prog.py
usage: prog.py [-h] echo
prog.py: error: the following arguments are required: echo
$ python3 prog.py --help
usage: prog.py [-h] echo
positional arguments:
echo
optional arguments:
-h, --help show this help message and exit
$ python3 prog.py foo
foo
Ось що відбувається:
We’ve added the
add_argument()
method, which is what we use to specify which command-line options the program is willing to accept. In this case, I’ve named itecho
so that it’s in line with its function.Для виклику нашої програми тепер потрібно вказати опцію.
The
parse_args()
method actually returns some data from the options specified, in this case,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)
І отримуємо:
$ python3 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
А тепер як щодо того, щоб зробити щось ще корисніше:
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)
Нижче наведено результат виконання коду:
$ python3 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)
Нижче наведено результат виконання коду:
$ python3 prog.py 4
16
$ python3 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")
І вихід:
$ python3 prog.py --verbosity 1
verbosity turned on
$ python3 prog.py
$ python3 prog.py --help
usage: prog.py [-h] [--verbosity VERBOSITY]
optional arguments:
-h, --help show this help message and exit
--verbosity VERBOSITY
increase output verbosity
$ python3 prog.py --verbosity
usage: prog.py [-h] [--verbosity VERBOSITY]
prog.py: error: argument --verbosity: expected one argument
Ось що відбувається:
Програма написана таким чином, щоб щось відображати, коли вказано
--verbosity
, і нічого не відображати, якщо ні.To show that the option is actually optional, there is no error when running the program without it. Note that by default, if an optional argument isn’t used, the relevant variable, in this case
args.verbosity
, is givenNone
as a value, which is the reason it fails the truth test of theif
statement.Довідкове повідомлення дещо інше.
При використанні опції
--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")
І вихід:
$ python3 prog.py --verbose
verbosity turned on
$ python3 prog.py --verbose 1
usage: prog.py [-h] [--verbose]
prog.py: error: unrecognized arguments: 1
$ python3 prog.py --help
usage: prog.py [-h] [--verbose]
optional arguments:
-h, --help show this help message and exit
--verbose increase output verbosity
Ось що відбувається:
The option is now more of a flag than something that requires a value. We even changed the name of the option to match that idea. Note that we now specify a new keyword,
action
, and give it the value"store_true"
. This means that, if the option is specified, assign the valueTrue
toargs.verbose
. Not specifying it impliesFalse
.Він скаржиться, коли ви вказуєте значення, у справжньому дусі того, чим насправді є прапори.
Зверніть увагу на інший текст довідки.
Короткі варіанти¶
Якщо ви знайомі з використанням командного рядка, ви помітите, що я ще не торкався теми коротких версій параметрів. Це досить просто:
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")
І ось:
$ python3 prog.py -v
verbosity turned on
$ python3 prog.py --help
usage: prog.py [-h] [-v]
optional arguments:
-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("the square of {} equals {}".format(args.square, answer))
else:
print(answer)
А тепер вихід:
$ python3 prog.py
usage: prog.py [-h] [-v] square
prog.py: error: the following arguments are required: square
$ python3 prog.py 4
16
$ python3 prog.py 4 --verbose
the square of 4 equals 16
$ python3 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("the square of {} equals {}".format(args.square, answer))
elif args.verbosity == 1:
print("{}^2 == {}".format(args.square, answer))
else:
print(answer)
І вихід:
$ python3 prog.py 4
16
$ python3 prog.py 4 -v
usage: prog.py [-h] [-v VERBOSITY] square
prog.py: error: argument -v/--verbosity: expected one argument
$ python3 prog.py 4 -v 1
4^2 == 16
$ python3 prog.py 4 -v 2
the square of 4 equals 16
$ python3 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("the square of {} equals {}".format(args.square, answer))
elif args.verbosity == 1:
print("{}^2 == {}".format(args.square, answer))
else:
print(answer)
І вихід:
$ python3 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)
$ python3 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
):
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)
We have introduced another action, «count», to count the number of occurrences of a specific optional arguments:
$ python3 prog.py 4
16
$ python3 prog.py 4 -v
4^2 == 16
$ python3 prog.py 4 -vv
the square of 4 equals 16
$ python3 prog.py 4 --verbosity --verbosity
the square of 4 equals 16
$ python3 prog.py 4 -v 1
usage: prog.py [-h] [-v] square
prog.py: error: unrecognized arguments: 1
$ python3 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
$ python3 prog.py 4 -vvv
16
Так, тепер це більше позначка (схожа на
action="store_true"
) у попередній версії нашого сценарію. Це має пояснити скаргу.Він також поводиться подібно до дії «store_true».
Тепер ось демонстрація того, що дає дія «підрахунок». Ви, напевно, бачили таке використання раніше.
І якщо ви не вкажете прапорець
-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("the square of {} equals {}".format(args.square, answer))
elif args.verbosity >= 1:
print("{}^2 == {}".format(args.square, answer))
else:
print(answer)
І ось що це дає:
$ python3 prog.py 4 -vvv
the square of 4 equals 16
$ python3 prog.py 4 -vvvv
the square of 4 equals 16
$ python3 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("the square of {} equals {}".format(args.square, answer))
elif args.verbosity >= 1:
print("{}^2 == {}".format(args.square, answer))
else:
print(answer)
Ми щойно представили ще одне ключове слово, default
. Ми встановили для нього значення 0
, щоб зробити його порівнянним з іншими значеннями int. Пам’ятайте, що за замовчуванням, якщо необов’язковий аргумент не вказано, він отримує значення None
, яке не можна порівняти зі значенням int (отже, виняток TypeError
).
і:
$ python3 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("{} to the power {} equals {}".format(args.x, args.y, answer))
elif args.verbosity >= 1:
print("{}^{} == {}".format(args.x, args.y, answer))
else:
print(answer)
Вихід:
$ python3 prog.py
usage: prog.py [-h] [-v] x y
prog.py: error: the following arguments are required: x, y
$ python3 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
$ python3 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("Running '{}'".format(__file__))
if args.verbosity >= 1:
print("{}^{} == ".format(args.x, args.y), end="")
print(answer)
Вихід:
$ python3 prog.py 4 2
16
$ python3 prog.py 4 2 -v
4^2 == 16
$ python3 prog.py 4 2 -vv
Running 'prog.py'
4^2 == 16
Конфліктні варіанти¶
So far, we have been working with two methods of an
argparse.ArgumentParser
instance. Let’s introduce a third one,
add_mutually_exclusive_group()
. It allows for us to specify options that
conflict with each other. Let’s also change the rest of the program so that
the new functionality makes more sense:
we’ll introduce the --quiet
option,
which will be the opposite of the --verbose
one:
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))
Наша програма стала простішою, і ми втратили деякі функції заради демонстрації. У будь-якому випадку, ось результат:
$ python3 prog.py 4 2
4^2 == 16
$ python3 prog.py 4 2 -q
16
$ python3 prog.py 4 2 -v
4 to the power 2 equals 16
$ python3 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
$ python3 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("{} to the power {} equals {}".format(args.x, args.y, answer))
else:
print("{}^{} == {}".format(args.x, args.y, answer))
Зверніть увагу на невелику різницю в тексті використання. Зверніть увагу на [-v | -q]
, який говорить нам, що ми можемо використовувати -v
або -q
, але не обидва одночасно:
$ python3 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
пропонує набагато більше, ніж показано тут. Його документи досить докладні та ретельні та повні прикладів. Пройшовши цей підручник, ви повинні легко засвоїти їх, не відчуваючи себе приголомшеними.