Argparse 教程 — Python 文档
Argparse 教程
- 作者
- Tshepang Lekhonkhobe
本教程旨在对 Python 标准库中推荐的命令行解析模块 argparse 进行温和的介绍。
笔记
还有其他两个模块可以完成相同的任务,即 getopt(相当于 C 语言中的 getopt()
)和已弃用的 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
这是正在发生的事情:
- 在没有任何选项的情况下运行脚本不会向标准输出显示任何内容。 没那么好用。
- 第二个开始展示 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
请注意,新功能也反映在帮助文本中。
结合 Positional 和 Optional 参数
我们的程序越来越复杂:
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)
我们引入了另一个动作“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”动作。
- 现在这里演示了“计数”操作的作用。 您以前可能见过这种用法。
- 如果您不指定
-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
请注意,到目前为止,我们一直在使用详细级别来 更改 显示的文本。 以下示例改为使用详细级别来显示 more 文本:
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