Argparse Tutorial
author: Tshepang Lekhonkhobe
翻译:田福顿
这份指导的目的在于简单的向大家的介绍argparse包,一个Python标准库中推荐使用的命令执行模块。这个教程是在Python3.X中运行调试完成的,会有一些使用细节与Python2.x不一致,特别是性能在python3.x中得到提升的异常处理方面。
Note
还有两个模块可以满足一样的功能,一个是getopt(等价于C语言中个的getopt()),另一个是不推荐使用的的optparse。值得注意的是argparse同样是基于optparse发展而来,所以在使用方法上两者有相似之处。
Concepts
让我们通过使用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命令时,它会默认显示当前目录内容、
·如果我们想在默认情况的基础上多了解一些,我们可以多告诉ls命令一些信息。在上述的例子中,当我们想要显示不同的目录信息,我们则在-ls 命令后制定了一个路径pypy。‘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]
optional arguments:
-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
发生了什么?
·当不带可选参数运行这段代码时,没有任何显示信息。
·第二次运行时程序开始显示一些关于argparse模块的信息,我们几乎没有(对这个模块)做什么事,但是我们已经可以得到不错的帮助信息了。
·–help选项(可以被缩写成-h)使我们唯一可以不同特别定义就能得到的功能。在没有定义其他命令时,使用出–help以外的可选命令都将抛出异常。
介绍位置参数
一个例子:
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
optional arguments:
-h, --help show this help message and exit
$ python prog.py foo
foo
发生了什么:
·我们添加了用来指定什么命令行选项可以被接受的add_argument()方法。在这个例子中,我们将其命名为‘echo’。
·现在我们的程序在调用时要求我们指定一个选项。
· parse_args() 方法实际上用来返回一些来自指定选项的数据,在这个例子中,返回的是echo。
·你不需要指定传入的值属于哪个变量,你也应当注意到变量名是匹配传入此方法的字符串参数的的,在这个例子中,则是将字符串“foo”传入“echo”
尽管help命令返回的帮助文本看起来已经足够好和完整了,但他还可以对我们更有帮助。举个例子,我们可以看echo作为位置参数,但是我们并不知道怎么用使用它。想要知道怎么使用echo我们只能靠猜和阅读源代码。现在,让我们将help变得更有用处。
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
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
代码运行结果:
$ 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将一切可选参数作为string来处理,除非我们告诉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]
optional arguments:
-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这个可选参数时,程序会打印一些信息,当没使用时则不会打印
·为了证明可选参是真的是可选的,这段程序在没有指定–verbosity 时运行也不会报错。注意它的默认情况,如果可选参数没有被使用,他的相关变量,在本例中就是 args.verbosity ,会被赋予一个None,这也就是为什么在使用 if args.verbosity: 时会返回False。
·当使用–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]
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"
结果是这样:
$ python prog.py -v
verbosity turned on
$ python 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
这是结果:
$ 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
不如我们给这段程序加上多个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
输出结果:
$ 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
除了最后一个,一切都运行得很好。我们程序出现了bug,现在让我们通过限制verbosity option可以接受的值,来修改这个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", 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
输出结果:
$ 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
optional arguments:
-h, --help show this help message and exit
-v {0,1,2}, --verbosity {0,1,2}
increase output verbosity
现在我们的修改同时也反映在了帮助文本里面。.
让我们通过不同的途径来调戏verbosity吧,这也符合了CPython的可执行文件处理自己的verbosity方式
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’,用来统计可选参数出现了多少次
$ 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
optional arguments:
-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’的功能。像“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
这是结果:
$ 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: unorderable types: NoneType() >= int()
呀,又出现了一个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,我们将他用来避免在和int值比较时出现的错误。在默认情况系如果可选参数没有给定一个值,会返回None,None不能和int进行比较,所以会出现 TypeError。 而现在,使用了default后,则会返回default的值。
$ python prog.py 4
16
我们目前所学习的知识,都还只是一些皮毛,argparse 的模块的功能是非常强大的,在这份指导结束之前,还有一些进阶的用法待学习。
进阶学习
到目前为止,我们已经学习argparse中的两种方法,现在是时候学习第三种噜。第三种是 add_mutually_exclusive_group()。它允许我们制定不能与其他可选参数共同使用的可选参数。现在我们来写改一下我们的程序,让我们能够更加直观的理解新功能。我们会介绍 –quite这个这个不能与 –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)
Our program is now simpler, and we’ve lost some functionality for the sake of demonstration. Anyways, here’s the output:
$ 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 "{} to the power {} equals {}".format(args.x, args.y, answer)
else:
print "{}^{} == {}".format(args.x, args.y, answer)
Note that slight difference in the usage text. Note the [-v | -q], which tells us that we can either use -v or -q, but not both at the same time:
$ 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
optional arguments:
-h, --help show this help message and exit
-v, --verbose
-q, --quiet
结论
argparse包的功能远比我们今天介绍了的来得多。它的说明文档也非常详细,而且有很多的例子来帮助理解。当你读完这个指南,你应当能轻松的消化掉里面的知识而且没有不堪重负的感觉。