使用argparse解析python命令行参数
今天讲一讲如何使python程序可以解析命令行参数。平时,我们在命令行下使用工具时,经常会附加参数,以获取扩展的功能,以linux下最简单的ls
为例(下面这个代码块摘自python文档Argparse Tutorial):
$ 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.
...
可见,如果我们能够在程序中加入命令行解析的功能,就可以给用户带来极大的便利。python中集成了一个非常好用的命令行解析模块argparse,下面我以x的y次幂为例,介绍一下argparse的使用方法(这个代码块同样摘自python文档Argparse Tutorial)。
import argparse
# initial a parser with description
parser = argparse.ArgumentParser(description="calculate X to the power of Y")
# add --verbose and --quiet to a mutually exclusive group, so that they conflict with each other
group = parser.add_mutually_exclusive_group()
# --verbose and --quiet are optional arguments
group.add_argument("-v", "--verbose", action="store_true")
group.add_argument("-q", "--quiet", action="store_true")
# x and y are positional(mandatory) arguments
parser.add_argument("x", type=int, help="the base")
parser.add_argument("y", type=int, help="the exponent")
# parse arguments, equivalent to **parser.parse_args(sys.argv[1:])**, but simpler
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))
我加了几行注释方便大家看,翻译成中文就是:
- 可以在生成parser的时候用descritption这个parameter对parser添加一个描述,效果参加下方输出;
- –verbose和–quiet是optional(可选)参数,x和y是positional(固定位置,可以理解为必选)参数,他们的区别就在于有无前置的减号
-
; - optional参数可以有缩写(长的用
--
开头,叫做name,多的用-
开头,叫做flag); - optional参数有2种用法,这里的verbose和quiet都是不带后续值的,带后续值的我会在文章最后的代码块里讲;
- position参数在使用时不必像optional参数那样显式声明参数名,直接将值放在对应位置即可;
- 对比我在之前一篇博客《带参数的python可执行文件
》里的例子,
parser.parse_args()
显然比parser.parse_args(sys.argv[1:])
要简单得多,而且不必import sys
,推荐。
letian@fengPC:~/myblog/examples$ python3 parser1.py -h
usage: parser1.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
letian@fengPC:~/myblog/examples$ python3 parser1.py 4 2
4^2 == 16
letian@fengPC:~/myblog/examples$ python3 parser1.py 4 2 -q
16
letian@fengPC:~/myblog/examples$ python3 parser1.py 4 2 -v
4 to the power 2 equals 16
letian@fengPC:~/myblog/examples$ python3 parser1.py 4 2 -vq
usage: parser1.py [-h] [-v | -q] x y
parser1.py: error: argument -q/--quiet: not allowed with argument -v/--verbose
letian@fengPC:~/myblog/examples$ python3 parser1.py 4 2 -v --quiet
usage: parser1.py [-h] [-v | -q] x y
parser1.py: error: argument -q/--quiet: not allowed with argument -v/--verbose
好的,最后,再来演示一下在含有main函数的python文件中,如何加入parser功能:
#!/usr/bin/python3
import argparse
def main(args):
answer = args.x**args.y
if args.bias:
answer += args.bias
if args.quiet:
print(answer)
elif args.verbose:
if args.bias:
print("{} to the power {} plus bias {} equals {}".format(args.x, args.y, args.bias, answer))
else:
print("{} to the power {} equals {}".format(args.x, args.y, answer))
else:
if args.bias:
print("{}^{}+{} == {}".format(args.x, args.y, args.bias, answer))
else:
print("{}^{} == {}".format(args.x, args.y, answer))
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="calculate X to the power of Y, then add a bias if you like")
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")
parser.add_argument("-b", "--bias", type=int, help="the bias")
main(parser.parse_args())
之所以将parser部分放在if __name__ == '__main__':
的代码块里,是因为这样可以防止这个python文件被import时仍然执行parser部分代码,但没有arguments可以拿来解析所带来的error,比如:
letian@fengPC:~/myblog/examples$ python3
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import parser1
usage: [-h] [-v | -q] x y
: error: the following arguments are required: x, y
letian@fengPC:~/myblog/examples$ python3
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import parser2
>>>
这样,如果想在import时仍然使用args,也可以手动生成args,再调用parser2.main(args)来实现。
最后,我们来看一下输出:
letian@fengPC:~/myblog/examples$ ./parser2.py -h
usage: parser2.py [-h] [-v | -q] [-b BIAS] x y
calculate X to the power of Y, then add a bias if you like
positional arguments:
x the base
y the exponent
optional arguments:
-h, --help show this help message and exit
-v, --verbose
-q, --quiet
-b BIAS, --bias BIAS the bias
letian@fengPC:~/myblog/examples$ ./parser2.py 3 2
3^2 == 9
letian@fengPC:~/myblog/examples$ ./parser2.py -b 5 3 2
3^2+5 == 14
letian@fengPC:~/myblog/examples$ ./parser2.py -q 3 2
9
letian@fengPC:~/myblog/examples$ ./parser2.py -q -b 5 3 2
14
letian@fengPC:~/myblog/examples$ ./parser2.py -v 3 2
3 to the power 2 equals 9
letian@fengPC:~/myblog/examples$ ./parser2.py -v -b 5 3 2
3 to the power 2 plus bias 5 equals 14
letian@fengPC:~/myblog/examples$ ./parser2.py -vq -b 5 3 2
usage: parser2.py [-h] [-v | -q] [-b BIAS] x y
parser2.py: error: argument -q/--quiet: not allowed with argument -v/--verbose
从这次开始,我会把文章中代码传到examples文件夹下,大家直接clone或者pull就可以执行了,免得还要复制粘贴,嘿嘿。
如果有发现我写错的地方,欢迎邮件联系我letian.feng@hotmail.com,或者直接在这个博客的repo里提pull request或issue也可以,谢谢!