argparse教程¶
- 作者
茨和邦-莱肯霍布
本教程旨在对 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]
options:
-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
options:
-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
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)
以下是运行代码的结果:
$ 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]
options:
-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]
options:
-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]
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)
现在输出:
$ 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(f"the square of {args.square} equals {answer}")
elif args.verbosity == 1:
print(f"{args.square}^2 == {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(f"the square of {args.square} equals {answer}")
elif args.verbosity == 1:
print(f"{args.square}^2 == {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
options:
-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(f"the square of {args.square} equals {answer}")
elif args.verbosity == 1:
print(f"{args.square}^2 == {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
options:
-h, --help show this help message and exit
-v, --verbosity increase output verbosity
$ python3 prog.py 4 -vvv
16
是的,它现在更像是一面旗帜(类似于
action="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(f"the square of {args.square} equals {answer}")
elif args.verbosity >= 1:
print(f"{args.square}^2 == {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(f"the square of {args.square} equals {answer}")
elif args.verbosity >= 1:
print(f"{args.square}^2 == {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(f"{args.x} to the power {args.y} equals {answer}")
elif args.verbosity >= 1:
print(f"{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
options:
-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(f"Running '{__file__}'")
if args.verbosity >= 1:
print(f"{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(f"{args.x} to the power {args.y} equals {answer}")
else:
print(f"{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
options:
-h, --help show this help message and exit
-v, --verbose
-q, --quiet
结论¶
这个 argparse
模块提供了比这里显示的更多的功能。它的文档非常详细和全面,并且有很多例子。通过本教程后,您应该可以轻松地消化它们,而不会感到不知所措。