Argparse 教程¶
作者: | Tshepang Lekhonkhobe |
---|
本教程旨在自然的讲解 argparse
,这个python标准库中推荐的命令行解析模块。
注意
有两个其他模块,可以实现相同的作用,即 getopt
(相当于 getopt()
从 C 语言) 和 已弃用的 optparse
。也要注意 argparse
是基于 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()
以下是运行代码的结果︰
$ 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
这里告诉你发生了什么︰
- 运行不带任何选项的脚本不会向stdout显示任何内容。没有那么有用。
- 第二个开始显示
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
这里是发生了什么:
- 我们已经添加的
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)
我们得到:
$ 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
时显示某些内容,否则不显示任何内容。 - 要显示该选项实际上是可选的,没有运行程序时没有错误。请注意,默认情况下,如果不使用可选参数,则相关变量(在此情况下为
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")
而输出:
$ 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
这是发生了什么:
- 该选项现在更多的是一个标志比需要一个值的东西。我们甚至更改了选项的名称以匹配该想法。请注意,我们现在指定一个新关键字
action
,并为其指定值"store_true"
。这意味着,如果指定了该选项,则将值True
分配给args.verbose
。未指定它意味着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")
这里:
$ 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
- 我们带回了一个位置论点,因此投诉。
- 注意顺序没有关系。
我们如何让我们的这个程序有能力有多个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,
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)
我们引入了另一个动作“count”来计算一个特定可选参数的出现次数:
$ 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”操作。
- 现在这里是一个“计数”动作给出的示例。你可能以前看过这种用法。
- 并且,与“store_true”操作一样,如果不指定
-v
标志,则该标志被认为具有None
值。 - 正如应该期望的,指定long形式的标志,我们应该得到相同的输出。
- 可悲的是,我们的帮助输出对于我们的脚本获得的新功能不是很有用,但是可以通过改进我们的脚本的文档来解决。通过
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: unorderable types: NoneType() >= int()
- 第一个输出运行良好,并修复了我们以前的错误。也就是说,我们希望任何值> = 2尽可能的冗长。
- 第三次输出不太好。
让我们修复这个bug:
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
互斥选项¶
到目前为止,我们一直在使用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("{} 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