Argparse 入门指南
本面入门指南意在介绍argparse这个python标准库中的命令行解析模块。该文章主要描述python 3.x中的argparse。部分细节与2.x中不同,尤其是某些报错信息,这些信息在3.x中有较好改进。
注意:有两个其他的模块也执行同样的任务,这两个模块分别为:1、getopt(一个和C语言中getopy()等价的东西);2、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:51cpython
drwxr-xr-x 4 wena wena 4096 Feb 8 12:04devguide
-rwxr-xr-x 1 wena wena 535 Feb 19 00:05prog.py
drwxr-xr-x 14 wena wena 4096 Feb 7 00:59 pypy
-rw-r--r-- 1 wena wena 741 Feb 18 01:01rm-unused-function.patch
$ ls --help
Usage: ls [OPTION]... [FILE]...
List information about the FILEs (thecurrent directory by default).
Sort entries alphabetically if none of-cftuvSUX nor --sort is specified.
...
从以上四条命令我们可以得到一些概念:
1、 在不添加任何可选项(-l –help之类)的情况下ls命令可用。其默认显示当前文件夹下的内容。
2、 如果我们想要默认情况以外的内容,我们可以添加一些具体的可选项。比如我们想显示不同文件夹pypy下的内容。我们所需要做的就是指定一个位置参数(positional argument)。它之所以被成为位置参数原因在于程序唯一的根据该值所在位置决定其应该执行什么操作。这个概念和cp这样的,基本用法为cp SRC DEST的命令更为相近。其一个位置参数SRC是想拷贝的文件源,第二个位置参数DEST则是目标文件夹路径。
3、 现在,我们打算改变程序的行为。在我们的例子中,我们想要显示更多的文件信息而不是仅仅显示文件名。可选参数(optionalargument)-l便可显示文件的详细信息。
4、 在最后一个帮助文本片段中的信息对于发现从未用过的可选命令有极大帮助,并且可以从帮助信息中理解其操作内容。
基础部分
让我们从一个简单到几乎啥都没干的例子开始:
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
代码所进行的操作内容如下:
1、 不带任何可选参数运行脚本(prog.py),得到啥都没有的标准输出。并不是很有用。
2、 第二个命令开始呈现argparse模块一些有用的内容。我们几乎啥都没干,但已经得到了一个友好的帮助信息。
3、 --help选项也可以缩写为-h,是一个我们可以”免费”(即不用定义)得到的可选参数。如果选择一些没有定义的可选参数将产生错误。即便如此我们也将”免费”获得一些有用的信息。
介绍位置参数(Positional arguments)
一个例子:
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 arerequired: 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
运行代码所做操作如下:
1、 我们添加了add_argument()方法,该方法允许我们定义程序能够响应的命令行选项。在上述代码中我们定义了一个echo位置参数,因此它将在命令行中执行它的功能。
2、 现在执行我们的脚本程序必须指定这个参数。
3、 parse_args()方法实际上返回了一些指定选项的数据,此处为echo。
4、 argparse”免费”以某种神奇的格式呈现变量(即无需指定值存储在哪个变量中)。你还会注意到方法的名称(args.echo中的echo)与传给add_argument()方法的字符串参数名称”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
于是我们获得:
$ python prog.py -h
usage: prog.py [-h] echo
positional arguments:
echo echo the string youuse 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()
printargs.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将我们输入的选项视为字符串,除非我们另外进行告知。所以我们应该告知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'
这样的结果较为理想。程序现在对非法的输入将给出有益的帮助信息。
介绍可选参数(Optional arguments)
至此我们主要探讨了位置参数(positional arguments)。让我们看一下如何添加可选参数:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--verbosity", help="increaseoutput verbosity")
args = parser.parse_args()
if args.verbosity:
print "verbosityturned 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
这里执行了如下行为:
1、 程序这样写的结果是,当—verbosity被指定时则输出某些内容(此处是”verbosity turned on”),反之则不输出任何东西。
2、 为了展示选项确实是可选的,这里当调用脚本程序时不输入可选项并没有报错。注意到默认情况下,如果某个可选参数没有被使用,其相关变量,这里是args.verbosity,将被赋予默认值None,这也是为什么此时if条件语句没有通过的原因。
3、 帮助信息有些不同。
4、 当使用—verbosity选项时,必须同时指定任意一个值。
以上例子在—verbosity选项下接受任意整型数值,但是对于我们的简单这个程序而言,只有True和False有实际用途。(因为if中statement仅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
所执行操作如下:
1、 选项此时更像是一个标签而不需要一个额外的数值参数。我们甚至修改了可选项名称使其与这个思想相符。注意到我们此时指定了一个新的关键词action,并赋予值”store_true”。这意味着,当选项被指定时,给args.verbose赋予True。没有指定则赋值False。
2、 这样做的原因在于当你指定一个值,实际上仅是想利用这个值作为一个标记而存在。
3、 注意观察帮助信息。
短选项
如果你熟悉命令行的使用,你会注意到我们还没有讨论过短版本的选项。它们较为简单:
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 andexit
-v, --verbose increase output verbosity
注意到新的功能也在帮助信息中反应。
位置参数和可选参数的组合
我们的程序逐渐复杂:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square",type=int,
help="display a squareof a given number")
parser.add_argument("-v","--verbose", action="store_true",
help="increase outputverbosity")
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 arerequired: 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 4equals 16
1、 We’ve brought back a positional argument, hence the complaint.
(我的理解是使用了action="store_true"所以收回了一个数值参数,才不会与square相混淆)
2、注意到选项的顺序与结果并没有关系
我们让verbosity可以有多个值,并能够实际使用:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square",type=int,
help="display a squareof a given number")
parser.add_argument("-v","--verbosity", type=int,
help="increase outputverbosity")
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的可选值范围来进行修正:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square",type=int,
help="display a squareof a given number")
parser.add_argument("-v","--verbosity", type=int, choices=[0, 1, 2],
help="increase outputverbosity")
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 asquare of a given number
optional arguments:
-h,--help show this help messageand exit
-v{0,1,2}, --verbosity {0,1,2}
increase outputverbosity
注意到这个改变同时反应在了错误信息提示和帮助信息中。
现在让我们用另一个相当常用的不同的方法来定义verbosity。同时它与Cpython的可执行文件处理verbosity参数的方式相符(查看下python –help的输出):
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square",type=int,
help="display thesquare of a given number")
parser.add_argument("-v","--verbosity", action="count",
help="increase outputverbosity")
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
我们引入了另一个action,”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 squareof a given number
optional arguments:
-h,--help show this help message andexit
-v,--verbosity increase output verbosity
$ python prog.py 4 -vvv
16
1、现在在我们之前脚本的版本中它更像是一个标签(与action=”store_true”相似)。
2、它的行为和”store_true”action相似。
3、以上验证了”count”action的用法。你可能曾经见过这类用法。
4、就像”store_true”action,如果你不指定-v标签,则标签的值为None。
5、正如所期望的,指定长形式的标签我们应该获得相同的输出。
6、比较糟糕的是输出的帮助信息对于我们脚本的新功能并没有很好的解释,但是我们同样可以通过help关键字来改进脚本的帮助信息。
7、最后一个输出暴露了我们程序的一个bug
修正:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square",type=int,
help="display a squareof a given number")
parser.add_argument("-v","--verbosity", action="count",
help="increase outputverbosity")
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()
1、 首先输出有所改善,修复了之前的bug。也就是对于任何大于等于2的值的处理。
2、 第三个输出并不理想。
修正bug:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square",type=int,
help="display a squareof a given number")
parser.add_argument("-v","--verbosity", action="count", default=0,
help="increase outputverbosity")
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使其在命令行没有进行该可选项输入的情况下能够与其他整型值进行对比。在没有使用该关键词前,若没有指定该可选参数则其值为None,导致其无法与整型值进行比较(因此导致TypeError错误)。
结果:
$ python 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
输出:
$ python prog.py
usage: prog.py [-h] [-v] x y
prog.py: error: the following arguments arerequired: x, y
$ python 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 andexit
-v,--verbosity
$ python prog.py 4 2 -v
4^2 == 16
注意到目前为止我们已经使用verbosity等级来改变文本的显示。接下来的例子不再是改变文本的显示而是通过verbosity等级从而显示更多的文本信息。
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),
print answer
输出:
$ python prog.py 4 2
16
$ python prog.py 4 2 -v
4^2 == 16
$ python 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)
我们的程序现在变得更加简单,同时为了演示我们去掉了一些功能。以下是输出:
$ 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: notallowed 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)
注意到在使用文本中有略微的不同。注意[-v | -q]它告诉我们不能同时使用-v和-q:
$ 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 andexit
-v,--verbose
-q, --quiet
结论
Argparse提供的不仅仅我们此处提到的这些功能。它的文档有更加细节的内容和丰富的例子。通过学习这个基础指南,你应该能够容易的吸收其文档内容而不是受到打击。
英文原文地址:https://docs.python.org/2/howto/argparse.html#id1
翻译有误请指出。转载请注明谢谢。