Argparse 教程

这篇教程旨在作为 argparse 的入门介绍,此模块是 Python 标准库中推荐的命令行解析模块。

注解:还有另外两个模块可以完成同样的任务,称为 getopt (对应于 C 语言中的 getopt() 函数) 和被弃用的 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]

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 模块的作用。我们几乎什么也没有做,但已经得到一条很好的帮助信息。
  • –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

optional arguments:
  -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

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)

以下是该代码的运行结果:

$ 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]

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 变量被指定的时候展示出来一些东西,当没有被指定的时候什么也不显示。
  • 展示了这个参数确实是可以选择的,当运行程序的时候不加它程序也不会报错,要显示该选项实际上是可选的,在运行没有该选项的程序时不会出现错误。注意,在默认情况下,如果没有使用可选参数,那么相关变量(在本例中为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]

optional arguments:
  -h, --help  show this help message and exit
  --verbose   increase output verbosity

程序运行情况如下:

  • 这个选项现在更多的是一个标志,而不是需要一个值的东西,我们甚至更改了选项的名称来匹配这个想法。注意,我们现在指定了一个新的关键字,动作,并给它赋值“store_true”。这意味着,如果指定了该选项,将Ture赋值给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]

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)

接着是输出:

$ 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
  • 我们带回了一个位置参数,因此出现了error。
  • 注意顺序无关紧要。
    回到它有的最初的功能,让它能够有多个冗余值,并实际使用它们:
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)

和输出:

$ 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("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

注意,更改还反映在错误消息和帮助字符串中。
现在,让我们用一种不同的方法来处理冗长,这是很常见的。它也匹配CPython可执行文件处理自己的冗长参数的方式 (check the output of 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)

我们引入了另一个活动”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
  • 它现在看起来更像是一个标志(就像 action=“store_true”)在我们之前的笔记中。这也可以解释产生的错误。
  • 它也表现得与 “store_true” 的行为相似。
  • 这个例子示范了把”count“赋值给action的现象,之前也出现这种用法。
  • 如果没有指定-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)

这是它给我们的输出:

$ 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。也就是说,我们希望任何 >= 2 的值尽可能详尽。
  • 第三组输出并不理想。

让我们修复那个 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。我们将它设置为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("{} to the power {} equals {}".format(args.x, args.y, answer))
elif args.verbosity >= 1:
    print("{}^{} == {}".format(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

optional arguments:
  -h, --help       show this help message and exit
  -v, --verbosity
$ python3 prog.py 4 2 -v
4^2 == 16

请注意,到目前为止,我们一直在使用冗余级别来更改显示的文本。下面的例子使用了冗余级别来显示更多的文本:

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), 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("{} to the power {} equals {}".format(args.x, args.y, answer))
else:
    print("{}^{} == {}".format(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

optional arguments:
  -h, --help     show this help message and exit
  -v, --verbose
  -q, --quiet

最后。。。给出python官方文档。。。其实我这个就是翻译人家得来的。

发布了32 篇原创文章 · 获赞 21 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Wolf_xujie/article/details/102786610
今日推荐