Argparse Tutorial

  • author

    • Tshepang Lekhonkhobe

本教程旨在对argparse(Python 标准库中推荐的命令行解析模块)进行简要介绍。这是为 Python 3 中的 argparse 编写的。2.x 中的一些细节有所不同,尤其是一些异常消息,在 3.x 中得到了改进。

Note

还有两个其他模块可以完成相同的任务,分别是getopt(与 C 语言中的getopt()等效)和不推荐使用的optparse。还要注意argparse基于optparse,因此在用法上非常相似。

Concepts

让我们展示一下我们将pass使用 ls 命令在本入门教程中探索的Function:

$ 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 命令很有用。默认情况下显示当前目录的内容。

  • 如果我们想要超出默认情况下提供的Function,请告诉我们更多信息。在这种情况下,我们希望它显示另一个目录pypy。我们所做的是指定所谓的位置参数。之所以这样命名,是因为程序应该仅根据其在命令行上的位置知道该值的用途。此概念与 cp 之类的命令更相关,该命令的最基本用法是cp SRC DEST。第一个位置是您要复制的内容,第二个位置是您要复制到的位置

  • 现在,假设我们要更改程序的行为。在我们的示例中,我们为每个文件显示更多信息,而不仅仅是显示文件名。在这种情况下,-l被称为可选参数。

  • 这是帮助文本的一小段。它非常有用,因为您可以遇到从未使用过的程序,只需阅读帮助文本即可了解其工作方式。

The basics

让我们从一个非常简单的示例开始,该示例几乎(什么)什么都不做:

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

这是正在发生的事情:

  • 如果不执行任何选项而运行脚本,则不会在 stdout 中显示任何内容。没那么有用。

  • 第二个开始显示argparse模块的用处。我们几乎什么也没做,但是已经得到了很好的帮助信息。

  • --help选项(也可以简称为-h)是我们免费获得的唯一选项(即无需指定)。指定其他任何内容都会导致错误。但是即使如此,我们仍然免费获得有用的使用信息。

介绍位置参数

An example:

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,以使其与其Function一致。

  • 现在调用我们的程序需要我们指定一个选项。

  • parse_args()方法实际上从指定的选项(在本例中为echo)返回一些数据。

  • 变量是argparse免费执行的某种形式的“魔术”(即,无需指定该值存储在哪个变量中)。您还将注意到,它的名称与方法echo的字符串参数匹配。

但是请注意,尽管帮助显示看起来不错,但目前并没有那么有用。例如,我们看到我们以echo作为位置参数,但是除了猜测或pass阅读源代码外,我们不知道它的作用。因此,让我们使其更加有用:

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会将我们给它的选项视为字符串,除非我们另有说明。因此,让我们告诉argparse将该 Importing 视为整数:

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'

一切顺利。现在,该程序甚至可以在 continue 进行之前,根据错误的非法 Importing 退出。

引入可选参数

到目前为止,我们一直在研究位置论证。让我们来看看如何添加可选的:

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作为值,这是其未能passif语句的真实性测试的原因。

  • 帮助消息有些不同。

  • 使用--verbosity选项时,还必须指定某个值,任何值。

上面的示例接受--verbosity的任意整数值,但是对于我们的简单程序,实际上只有两个值是TrueFalse有用。让我们相应地修改代码:

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

  • 当您实际指定标志的实际含义时,它会抱怨。

  • 请注意不同的帮助文本。

Short options

如果您熟悉命令行用法,您会发现我还没有涉及这些选项的简短版本的 Topic。很简单:

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

请注意,新Function也反映在帮助文本中。

组合位置和可选参数

我们的程序越来越复杂:

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
  • 我们提出了一个立场论据,因此提出了申诉。

  • 注意 Sequences 无关紧要。

我们如何让我们这个程序具有多个详细值并实际使用它们的能力:

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

除了最后一个显示了我们程序中的错误之外,所有这些看起来都很不错。让我们pass限制--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

并输出:

$ 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

请注意,更改还反映在错误消息以及帮助字符串中。

现在,让我们使用另一种非常详细的演奏方式。它还与 CPython 可执行文件处理其自己的冗长参数的方式匹配(检查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”,以计算特定可选参数的出现次数:

$ 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”操作。

  • 现在,这里展示了“计数”操作的作用。您以前可能已经看过这种用法。

  • 并且,就像“ store_true”操作一样,如果您未指定-v标志,则该标志被视为具有None值。

  • 如预期的那样,指定标志的长格式,我们应该获得相同的输出。

  • 令人遗憾的是,我们的帮助输出不能很好地说明脚本已获得的新Function,但是可以pass改进脚本文档(例如passhelp关键字参数)来解决此问题。

  • 最后的输出暴露了我们程序中的错误。

Let's fix:

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()
  • 第一个输出运行良好,并修复了我们之前遇到的错误。也就是说,我们希望任何> = 2 的值都尽可能详细。

  • 第三输出不是很好。

让我们修复该错误:

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异常)。

And:

$ python prog.py 4
16

就目前为止所学到的知识而言,您可以走的很远,而我们只是从头开始。 argparse模块非常强大,在结束本教程之前,我们将对其进行更多的探索。

进阶一点

如果我们想扩展我们的 Servlets 以执行其他Function,而不仅仅是正方形,该怎么办:

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

Output:

$ python prog.py
usage: prog.py [-h] [-v] x y
prog.py: error: the following arguments are required: 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 and exit
  -v, --verbosity
$ python prog.py 4 2 -v
4^2 == 16

请注意,到目前为止,我们一直在使用详细级别来“更改”要显示的文本。下面的示例改为使用详细级别来显示* more *文本:

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

Output:

$ 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

Conflicting options

到目前为止,我们一直在使用argparse.ArgumentParser实例的两种方法。让我们介绍第三个add_mutually_exclusive_group()。它允许我们指定相互冲突的选项。我们还要更改程序的其余部分,以便使新Function更有意义:我们将引入--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)

现在,我们的程序更加简单,为演示起见,我们已经失去了一些Function。无论如何,这是输出:

$ 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

那应该很容易理解。我添加了最后一个输出,以便您可以看到所获得的灵 Active,即将长格式选项与短格式选项混合在一起。

在总结之前,您可能想告诉您的用户程序的主要目的,以防万一他们不知道:

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 and exit
  -v, --verbose
  -q, --quiet

Conclusion

argparse模块提供的Function远远超过此处显示的内容。它的文档非常详细,透彻,并有许多示例。阅读完本教程后,您应该轻松消化它们而不会感到不知所措。