首页 > 其他 > 详细

argparse模块简明教程

时间:2020-10-08 18:29:25      阅读:23      评论:0      收藏:0      [点我收藏+]

前言:阅读源码时遇到argparse库,我为了理解用法找了不少博客,要么晦涩难懂,要么讲的太浅。最后还是看了官方英文教程,讲得非常清楚。本文大部分内容都来源于官方教程,我做了小小的翻译和整理工作,为英文不太好的同学节省一下时间。这篇文章略长,但我相信只要你从头读到尾,一定可以很好地理解argparse的用法。
转载请注明出处哦

1 argparse是干什么的

我们在写python程序的时候,有时候希望在执行的时候附加一些参数。为了在程序中使用这些附加参数,我们需要正确地解析它们,这个时候argparse就派上用场了,argparse是一款简单而又强大的命令行解析工具。

2 命令行参数的概念

首先,让我们看看Linux中常用的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文件夹里的内容,该怎么做呢?实际上我们指定了一个位置参数 pypy,之所以叫位置参数,是因为仅仅凭借它的位置信息,解析器就知道该怎么做。就比如cp命令,基础的使用方法是cp SRC DEST,第一个位置是想要复制的文件,第二个位置是想要复制到的地方。
  • 现在,我们想要改变程序的行为。在上面的例子中,我们想展示每个文件的更多信息,而不仅仅是文件名。-l做了这件事,它被称为可选参数
  • 指定--help会展示帮助文档,当遇到一个从来没用过的程序时,帮助文档能够让你明白程序如何运作。

3 从一个简单的例子开始

让我们从一个简单到几乎什么也不做的例子,来开始argparse的学习:

# prog.py
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的用处,我们在prog.py脚本里几乎什么也没做,但是我们已经拥有了一个帮助文档,只要指定--help就可以展示它
  • --help参数也可以用更简短的-h来替代,它们是argparse唯一的免费参数,哈哈,之所以说是免费,是因为我们无需在程序中定义它们的行为就拥有了它们,观察prog.py,并没有任何和--help相关的代码。但是,除了--help-h之外,指定任何其他的附加参数都会报错,因为我们没有在程序中定义它们。接下来我会介绍如何定义自己的参数。

4 介绍位置参数

看这个例子:

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的参数
  • 现在我们执行程序会要求我们给出参数echo的值,不然就像第一行一样报错:the following arguments are required: echo
  • parse_args()会返回用户给出的参数值,在这个例子中,是echo参数的值。
  • parse_args()返回的参数的值可以通过 .参数名 获得,这个例子里,我们通过args.echo就可以得到echo的参数值,是我们传的字符串‘foo‘。注意,这个参数名就是我们在add_argument函数里给出的字符串‘echo‘。
    看看上面--help输出的帮助文档,虽然看起来已经很不错了,但是并不是很有帮助。比如,通过帮助文档,我们知道echo是一个位置参数,但是并不知道它是什么,除了看prog.py的源代码我们根本不知道这个参数的作用是啥。所以,来让它更有用吧:
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)

上面的程序功能是从命令行读取一个位置参数square,然后打印它的平方值。
看看执行过程:

$ 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应该将输入视作int类型:

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‘

哇,很完美有没有,程序现在可以很好地运作了。而且你发现没,当我们输入four作为参数时,这不是一个数字,如果不使用argparse,我们要到运算平方的时候才报类型错误,现在在参数解析的时候程序就会因为类型不匹配提前退出,很棒吧。

5 介绍可选参数

到目前为止我们一直在和位置参数打交道,让我们看看怎么添加可选参数吧!

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输出一些东西,反之什么也不输出
  • 定义可选参数的方法是在参数名前面加两道横杠--
  • 为了证明可选参数真的是可选的,看上面的执行过程,当我们不指定--verbosity的时候程序没有报错,这就说明可选参数真的是可选的嗷。注意!当我们在程序中定义了可选参数,但是在执行的时候没有用它,比如这个例子中的args.verbosity,那么它的默认值是None,这也就是在不指定--verbosity时,if语句会False的原因。

上面的例子中,我们需要接受一个任意值给--verbosity。但实际上,我们希望指定--verbosity时,args.verbosity为True,不指定为False就够了。能不能不指定一个值给--verbosity呢?看看这个例子

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

观察上面的代码和执行过程,发现了什么?

  • 现在这个--verbose选项更像是一个flag(标志),而不是需要指定一个值的参数。我们用了一个新keyword,action,并且给了它一个值"store_true",这意味着,如果执行程序时指定了--verbose标志,就把True赋给args.verbose,如果没有指定,就把False赋给它
  • 现在,如果你还要给--verbose指定一个值,它就会报错!
  • 注意帮助文档的变化

简短参数(short options)

如果你熟悉命令行的操作,你就会注意到,截至目前,我还没有讨论简短参数。什么是简短参数呢?比如--help,可以用-h代替,一个横杠开头的-h就是简短参数。其实定义简短参数非常简单:

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

注意帮助文档的变化。

6 结合使用位置参数和可选参数

来看一个更复杂的例子:

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
  • 现在,我们定义了位置参数square,所以你不给它指定一个值程序就会报错
  • 注意,可选参数并不影响位置参数的位置,所以它们的顺序无所谓。
    好了,我们来试试让--verbosity不再是flag,而是给它指定一个数字,如果数字越大,程序输出的屁话(误)越多。修改程序如下:
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)

看出区别了吗,我们把--verbosity的type设成了int,并且把action=‘store_true‘去掉了。这样就要指定一个数字给它。
执行代码:

$ 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

看起来很不错!除了最后一个,我们不希望赋3给verbosity时它反而输出一个更短的句子,这是我们程序中的一个bug。让我们来修复这个bug,将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

注意报错信息和帮助文档的变化。

好,接下来,让我们来看看还能把这个verbosity玩出什么花活,其实也是很常用的玩法,CPython解释器的verbosity参数就是这种玩法,你可以执行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)

这里引入了另一个新的action,“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
  • 现在-v/--verbosity看起来更像是一个flag(和action=‘store_true‘有点类似),当你给--verbosity指定一个值就会报错。
  • 注意,如果你不指定-v或者--verbosity,args.verbosity的值不是0,而是None!这会导致Bug,待会说。
  • 根据我们程序的需要,当指定三个以上的v,也应该和指定两个v的输出相同(两个v就输出了很多屁话了,说不出更多的屁话了)
  • 有点不幸的是,帮助文档这次没有表现出有用的信息,它没告诉我们可以多次指定v来获得更详尽的输出。
  • 最后一个执行结果也是我们程序的一个bug,指定了三个v却得到很短的输出。
    让我们来修复一下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",
                    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‘
  • 前两个输出很不错,修复了我们之前的bug
  • 第三个输出存在问题。这就是我上面提到的,如果不指定-v,args.verbosity的值是None,而不是0!
    让我们修复第三个输出的问题:
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)

我们引入了一个新的keyword,default,我们将它设为0,这样在不指定-v时,args.verbosity被设为0,就可以和其他数字比较了!记住,如果某个可选参数在执行时没有被指定,就会赋None值给它,而None是无法和int值做比较的!解决办法就是给它一个defualt值。
现在:

$ python3 prog.py 4
16

总结

根据上面所学的知识,你已经可以做非常非常多的事了,但实际上我们也只涉及到argparse强大功能的表面而已。argparse非常强大,如果有需要,大伙可以查阅argparse的官方api文档
码字不易,如果觉得文章不错的话,点个赞再走吧,秋梨膏!

argparse模块简明教程

原文:https://www.cnblogs.com/mmxy/p/13779761.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!