optparse — 命令行选项解析器

源代码: Lib/optparse.py


选择一个参数解析库

标准库包含三个参数解析库

  • getopt:一个模块,紧密地反映了过程式 C getopt API。自初始 Python 1.0 版本发布之前就已包含在标准库中。

  • optparsegetopt 的声明式替代方案,提供等效的功能,而无需每个应用程序实现自己的过程式选项解析逻辑。自 Python 2.3 版本起包含在标准库中。

  • argparse:一个比 optparse 更具主观性的替代方案,默认情况下提供更多功能,但代价是降低了应用程序在精确控制参数处理方式方面的灵活性。自 Python 2.7 和 Python 3.2 版本起包含在标准库中。

在没有更具体的参数解析设计约束的情况下,argparse 是实现命令行应用程序的推荐选择,因为它以最少的应用程序级别代码提供了最高级别的基线功能。

getopt 几乎完全出于向后兼容的原因而保留。但是,它也作为在基于 getopt 的 C 应用程序中原型设计和测试命令行参数处理的工具,服务于一个小众用例。

optparse 在以下情况下应被视为 argparse 的替代方案

  • 应用程序已在使用 optparse,并且不想冒险迁移到 argparse 时可能出现的细微行为变化

  • 应用程序需要对命令行上选项和位置参数的交错方式进行额外的控制(包括完全禁用交错功能的能力)

  • 应用程序需要对命令行元素的增量解析进行额外的控制(虽然 argparse 支持此功能,但它在实践中的确切工作方式对于某些用例来说是不希望的)

  • 应用程序需要对接受可能以 - 开头的参数值的选项的处理进行额外的控制(例如要传递给调用的子进程的委派选项)

  • 应用程序需要一些 argparse 不支持的其他命令行参数处理行为,但可以使用 optparse 提供的较低级别接口来实现

这些考虑因素还意味着,对于编写第三方命令行参数处理库的库作者来说,optparse 可能提供更好的基础。

作为一个具体的例子,请考虑以下两种命令行参数解析配置,第一种使用 optparse,第二种使用 argparse

import optparse

if __name__ == '__main__':
    parser = optparse.OptionParser()
    parser.add_option('-o', '--output')
    parser.add_option('-v', dest='verbose', action='store_true')
    opts, args = parser.parse_args()
    process(args, output=opts.output, verbose=opts.verbose)
import argparse

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('-o', '--output')
    parser.add_argument('-v', dest='verbose', action='store_true')
    parser.add_argument('rest', nargs='*')
    args = parser.parse_args()
    process(args.rest, output=args.output, verbose=args.verbose)

最明显的区别是,在 optparse 版本中,非选项参数在选项处理完成后由应用程序单独处理。在 argparse 版本中,位置参数的声明和处理方式与命名选项相同。

但是,argparse 版本还会以不同于 optparse 版本处理某些参数组合的方式来处理它们。例如(除其他差异外)

  • 提供 -o -v 在使用 optparse 时会给出 output="-v"verbose=False,但在使用 argparse 时会给出用法错误(抱怨没有为 -o/--output 提供值,因为 -v 被解释为表示详细标志)

  • 同样,提供 -o -- 在使用 optparse 时会给出 output="--"args=(),但在使用 argparse 时会给出用法错误(也抱怨没有为 -o/--output 提供值,因为 -- 被解释为终止选项处理并将所有剩余值视为位置参数)

  • 当使用 optparse 时,提供 -o=foo 会得到 output="=foo",而使用 argparse 则会得到 output="foo"(因为 = 被特殊处理为选项参数值的替代分隔符)。

argparse 版本中,这些不同的行为是否被认为是期望的或问题,将取决于具体的命令行应用程序用例。

另请参阅

click 是一个第三方参数处理库(最初基于 optparse),它允许将命令行应用程序开发为一组装饰的命令实现函数。

其他第三方库,例如 typermsgspec-click,允许以更有效地与 Python 类型注解的静态检查集成的方式指定命令行接口。

简介

optparse 是一个比极简的 getopt 模块更方便、更灵活和更强大的命令行选项解析库。optparse 使用一种更具声明式的命令行解析风格:您创建一个 OptionParser 的实例,用选项填充它,并解析命令行。optparse 允许用户以传统的 GNU/POSIX 语法指定选项,并为您生成用法和帮助消息。

这是一个在简单脚本中使用 optparse 的示例

from optparse import OptionParser
...
parser = OptionParser()
parser.add_option("-f", "--file", dest="filename",
                  help="write report to FILE", metavar="FILE")
parser.add_option("-q", "--quiet",
                  action="store_false", dest="verbose", default=True,
                  help="don't print status messages to stdout")

(options, args) = parser.parse_args()

使用这几行代码,您的脚本用户现在可以在命令行上执行“通常的操作”,例如

<yourscript> --file=outfile -q

当解析命令行时,optparse 根据用户提供的命令行值设置由 parse_args() 返回的 options 对象的属性。当 parse_args() 从解析此命令行返回时,options.filename 将为 "outfile",而 options.verbose 将为 Falseoptparse 支持长选项和短选项,允许将短选项合并在一起,并允许以多种方式将选项与其参数关联。因此,以下命令行都等效于上述示例

<yourscript> -f outfile --quiet
<yourscript> --quiet --file outfile
<yourscript> -q -foutfile
<yourscript> -qfoutfile

此外,用户可以运行以下命令之一

<yourscript> -h
<yourscript> --help

optparse 将打印出您的脚本选项的简要摘要

Usage: <yourscript> [options]

Options:
  -h, --help            show this help message and exit
  -f FILE, --file=FILE  write report to FILE
  -q, --quiet           don't print status messages to stdout

其中 yourscript 的值在运行时确定(通常来自 sys.argv[0])。

背景

optparse 被明确设计为鼓励创建具有简单命令行界面的程序,这些界面遵循 C 开发人员可用的 getopt() 系列函数建立的约定。为此,它仅支持 Unix 下常用的最常见的命令行语法和语义。如果您不熟悉这些约定,阅读本节将使您熟悉它们。

术语

参数

在命令行中输入的字符串,由 shell 传递给 execl()execv()。在 Python 中,参数是 sys.argv[1:] 的元素(sys.argv[0] 是正在执行的程序的名称)。Unix shell 也使用术语“词”。

有时需要替换 sys.argv[1:] 以外的参数列表,因此您应该将“参数”理解为“sys.argv[1:] 的元素,或作为 sys.argv[1:] 的替代提供的其他列表的元素”。

选项

用于提供额外信息以指导或自定义程序执行的参数。选项有许多不同的语法;传统的 Unix 语法是一个连字符(“-”)后跟一个字母,例如 -x-F。此外,传统的 Unix 语法允许将多个选项合并为单个参数,例如 -x -F 等效于 -xF。GNU 项目引入了 -- 后跟一系列连字符分隔的单词,例如 --file--dry-run。这些是 optparse 提供的仅有的两种选项语法。

世界上出现的一些其他选项语法包括

  • 一个连字符后跟几个字母,例如 -pf(这与合并为单个参数的多个选项相同)

  • 一个连字符后跟一个完整的单词,例如 -file(这在技术上等效于前一种语法,但它们通常不会在同一程序中看到)

  • 一个加号后跟一个字母、几个字母或一个单词,例如 +f, +rgb

  • 一个斜杠后跟一个字母、几个字母或一个单词,例如 /f, /file

这些选项语法不受 optparse 支持,并且永远不会支持。这是故意的:前三个在任何环境下都是非标准的,而最后一个只有当您专门针对 Windows 或某些旧平台(例如 VMS、MS-DOS)时才有意义。

选项参数

一个跟随选项的参数,与该选项紧密相关,并在该选项出现时从参数列表中消耗掉。使用 optparse,选项参数可能与其选项在单独的参数中

-f foo
--file foo

或包含在同一参数中

-ffoo
--file=foo

通常,给定的选项要么接受一个参数,要么不接受。很多人想要“可选选项参数”功能,这意味着一些选项如果看到它就会接受一个参数,如果看不到就不会接受。这有点争议,因为它使解析模糊不清:如果 -a 接受一个可选参数,而 -b 是另一个完全不同的选项,我们如何解释 -ab?由于这种模糊性,optparse 不支持此功能。

位置参数

在解析选项后,即在解析选项及其参数并从参数列表中删除后,参数列表中剩余的内容。

必需选项

必须在命令行上提供的选项;请注意,“必需选项”一词在英语中是自相矛盾的。optparse 不会阻止您实现必需选项,但也不会对此提供太多帮助。

例如,考虑以下假设的命令行

prog -v --report report.txt foo bar

-v--report 都是选项。假设 --report 接受一个参数,则 report.txt 是一个选项参数。foobar 是位置参数。

选项的用途是什么?

选项用于提供额外信息来调整或自定义程序的执行。以防万一不清楚,选项通常是可选的。程序应该能够在没有任何选项的情况下正常运行。(从 Unix 或 GNU 工具集中选择一个随机程序。它可以在没有任何选项的情况下运行并仍然有意义吗?主要的例外是 findtardd,所有这些都是因其非标准语法和令人困惑的界面而受到批评的变异怪胎。)

很多人希望他们的程序具有“必需选项”。想一想。如果它是必需的,那么它就不是可选的!如果您的程序绝对需要某些信息才能成功运行,那么这就是位置参数的用途。

作为良好命令行界面设计的一个示例,请考虑用于复制文件的简单 cp 实用程序。尝试在不提供目标和至少一个源的情况下复制文件没有多大意义。因此,如果您在没有参数的情况下运行 cp,它会失败。但是,它具有灵活、有用的语法,根本不需要任何选项

cp SOURCE DEST
cp SOURCE ... DEST-DIR

仅仅使用这些,你就可以走得很远。大多数 cp 实现都提供了一系列选项来精确调整文件的复制方式:你可以保留模式和修改时间,避免跟随符号链接,在覆盖现有文件之前询问等等。但是,所有这些都不会分散 cp 的核心任务,即将一个文件复制到另一个文件,或者将多个文件复制到另一个目录。

位置参数是用来做什么的?

位置参数用于那些你的程序绝对、明确需要运行的信息。

一个好的用户界面应该尽可能减少绝对要求。如果你的程序需要 17 个不同的信息才能成功运行,那么如何从用户那里获取这些信息并不重要——大多数人会在成功运行程序之前放弃并走开。这适用于用户界面是命令行、配置文件还是 GUI:如果你对用户提出如此多的要求,他们中的大多数人会直接放弃。

简而言之,尽量减少用户绝对需要提供的信息量——尽可能使用合理的默认值。当然,你也希望你的程序具有合理的灵活性。这就是选项的用途。同样,它们是配置文件中的条目、GUI “首选项” 对话框中的小部件,还是命令行选项并不重要——你实现的选项越多,你的程序就越灵活,其实现就越复杂。当然,过多的灵活性也有缺点;太多的选项可能会让用户感到不知所措,并使你的代码更难维护。

教程

虽然 optparse 非常灵活且功能强大,但在大多数情况下使用也很简单。本节介绍任何基于 optparse 的程序中常见的代码模式。

首先,你需要导入 OptionParser 类;然后,在主程序的早期,创建一个 OptionParser 实例

from optparse import OptionParser
...
parser = OptionParser()

然后你可以开始定义选项。基本语法是

parser.add_option(opt_str, ...,
                  attr=value, ...)

每个选项都有一个或多个选项字符串,例如 -f--file,以及几个选项属性,这些属性告诉 optparse 在命令行上遇到该选项时应该期待什么以及应该做什么。

通常,每个选项都会有一个短选项字符串和一个长选项字符串,例如

parser.add_option("-f", "--file", ...)

你可以自由定义任意数量的短选项字符串和任意数量的长选项字符串(包括零),只要总体上至少有一个选项字符串即可。

传递给 OptionParser.add_option() 的选项字符串实际上是由该调用定义的选项的标签。为简洁起见,我们将经常提到在命令行上遇到一个选项;实际上,optparse 遇到的是选项字符串,并从中查找选项。

定义完所有选项后,指示 optparse 解析程序的命令行

(options, args) = parser.parse_args()

(如果你愿意,可以将自定义参数列表传递给 parse_args(),但这很少是必要的:默认情况下它使用 sys.argv[1:]。)

parse_args() 返回两个值

  • options,一个包含所有选项值的对象——例如,如果 --file 接受一个字符串参数,那么 options.file 将是用户提供的文件名,如果用户没有提供该选项,则为 None

  • args,解析选项后剩余的位置参数列表

本教程部分仅涵盖四个最重要的选项属性:actiontypedest(目标)和 help。其中,action 是最基本的。

理解选项动作

动作告诉 optparse 当它在命令行上遇到一个选项时应该做什么。optparse 中硬编码了一组固定的动作;添加新动作是 扩展 optparse 部分中涵盖的高级主题。大多数动作告诉 optparse 将一个值存储到某个变量中——例如,从命令行获取一个字符串并将其存储为 options 的属性。

如果你没有指定选项动作,optparse 默认为 store

store 动作

最常见的选项动作是 store,它告诉 optparse 获取下一个参数(或当前参数的剩余部分),确保其类型正确,并将其存储到你选择的目标。

例如

parser.add_option("-f", "--file",
                  action="store", type="string", dest="filename")

现在让我们编造一个假的命令行,并要求 optparse 解析它

args = ["-f", "foo.txt"]
(options, args) = parser.parse_args(args)

optparse 看到选项字符串 -f 时,它会消耗下一个参数 foo.txt,并将其存储在 options.filename 中。因此,在调用 parse_args() 后,options.filename"foo.txt"

optparse 支持的其他一些选项类型是 intfloat。这是一个期望整数参数的选项

parser.add_option("-n", type="int", dest="num")

请注意,此选项没有长选项字符串,这是完全可以接受的。此外,没有显式动作,因为默认值为 store

让我们解析另一个假的命令行。这一次,我们将选项参数紧贴选项:因为 -n42(一个参数)等效于 -n 42(两个参数),所以代码

(options, args) = parser.parse_args(["-n42"])
print(options.num)

将打印 42

如果你没有指定类型,optparse 假设为 string。结合默认动作是 store 这一事实,这意味着我们的第一个示例可以更短

parser.add_option("-f", "--file", dest="filename")

如果你不提供目标(destination),optparse 会根据选项字符串推断出一个合理的默认值:如果第一个长选项字符串是 --foo-bar,那么默认目标是 foo_bar。如果没有长选项字符串,optparse 会查看第一个短选项字符串:-f 的默认目标是 f

optparse 还包括内置的 complex 类型。添加类型将在 扩展 optparse 部分介绍。

处理布尔(标志)选项

标志选项——当看到特定选项时,将变量设置为 true 或 false——非常常见。optparse 通过两个不同的动作支持它们,store_truestore_false。例如,你可能有一个 verbose 标志,可以使用 -v 打开,使用 -q 关闭。

parser.add_option("-v", action="store_true", dest="verbose")
parser.add_option("-q", action="store_false", dest="verbose")

这里我们有两个具有相同目标的不同选项,这完全没问题。(这只是意味着你在设置默认值时需要小心一点——见下文。)

optparse 在命令行中遇到 -v 时,它会将 options.verbose 设置为 True;当它遇到 -q 时,options.verbose 被设置为 False

其他动作

optparse 支持的其他一些动作是

"store_const"

存储一个常量值,通过 Option.const 预先设置

"append"

将此选项的参数附加到列表中

"count"

将计数器加一

"callback"

调用指定的函数

这些在 参考指南选项回调 部分中介绍。

默认值

以上所有示例都涉及在看到某些命令行选项时设置某个变量(“目标”)。如果从未看到这些选项会发生什么?由于我们没有提供任何默认值,它们都被设置为 None。这通常没问题,但有时你希望有更多的控制权。optparse 允许你为每个目标提供默认值,该默认值在解析命令行之前分配。

首先,考虑 verbose/quiet 示例。如果我们希望 optparseverbose 设置为 True,除非看到 -q,那么我们可以这样做

parser.add_option("-v", action="store_true", dest="verbose", default=True)
parser.add_option("-q", action="store_false", dest="verbose")

由于默认值应用于目标而不是任何特定选项,并且这两个选项恰好具有相同的目标,这完全等效

parser.add_option("-v", action="store_true", dest="verbose")
parser.add_option("-q", action="store_false", dest="verbose", default=True)

考虑这个

parser.add_option("-v", action="store_true", dest="verbose", default=False)
parser.add_option("-q", action="store_false", dest="verbose", default=True)

同样,verbose 的默认值将是 True:为任何特定目标提供的最后一个默认值是有效的。

指定默认值的更清晰的方法是 OptionParser 的 set_defaults() 方法,你可以在调用 parse_args() 之前的任何时间调用它。

parser.set_defaults(verbose=True)
parser.add_option(...)
(options, args) = parser.parse_args()

和以前一样,为给定选项目标指定的最后一个值是有效的。为了清楚起见,请尝试使用一种方法或另一种方法来设置默认值,而不是两者都用。

生成帮助

optparse 自动生成帮助和用法文本的能力对于创建用户友好的命令行界面非常有用。你所要做的就是为每个选项提供一个 help 值,以及可选的整个程序的简短用法消息。这是一个填充了用户友好(已文档化)选项的 OptionParser

usage = "usage: %prog [options] arg1 arg2"
parser = OptionParser(usage=usage)
parser.add_option("-v", "--verbose",
                  action="store_true", dest="verbose", default=True,
                  help="make lots of noise [default]")
parser.add_option("-q", "--quiet",
                  action="store_false", dest="verbose",
                  help="be vewwy quiet (I'm hunting wabbits)")
parser.add_option("-f", "--filename",
                  metavar="FILE", help="write output to FILE")
parser.add_option("-m", "--mode",
                  default="intermediate",
                  help="interaction mode: novice, intermediate, "
                       "or expert [default: %default]")

如果 optparse 在命令行中遇到 -h--help,或者你只是调用 parser.print_help(),它会将以下内容打印到标准输出

Usage: <yourscript> [options] arg1 arg2

Options:
  -h, --help            show this help message and exit
  -v, --verbose         make lots of noise [default]
  -q, --quiet           be vewwy quiet (I'm hunting wabbits)
  -f FILE, --filename=FILE
                        write output to FILE
  -m MODE, --mode=MODE  interaction mode: novice, intermediate, or
                        expert [default: intermediate]

(如果帮助输出由帮助选项触发,optparse 会在打印帮助文本后退出。)

这里有很多内容可以帮助 optparse 生成最佳帮助消息

  • 脚本定义了自己的用法消息

    usage = "usage: %prog [options] arg1 arg2"
    

    optparse 将用法字符串中的 %prog 扩展为当前程序的名称,即 os.path.basename(sys.argv[0])。然后,扩展的字符串会在详细的选项帮助之前打印。

    如果你不提供用法字符串,optparse 会使用一个平淡但合理的默认值:"用法: %prog [选项]",如果你的脚本不接受任何位置参数,这很好。

  • 每个选项都定义一个帮助字符串,并且不用担心换行——optparse 会负责换行并使帮助输出看起来不错。

  • 接受值的选项在其自动生成的帮助消息中指示此事实,例如,对于“mode”选项

    -m MODE, --mode=MODE
    

    在这里,“MODE”被称为元变量:它代表用户希望提供给 -m/--mode 的参数。默认情况下,optparse 将目标变量名转换为大写,并将其用作元变量。有时,这不是你想要的——例如,--filename 选项显式设置 metavar="FILE",从而产生此自动生成的选项描述

    -f FILE, --filename=FILE
    

    但这不仅仅是为了节省空间:手动编写的帮助文本使用元变量 FILE 来暗示用户,在半正式语法 -f FILE 和非正式语义描述“将输出写入 FILE”之间存在联系。这是一种简单但有效的方法,可以使你的帮助文本更清晰,对最终用户更有用。

  • 具有默认值的选项可以在帮助字符串中包含 %default——optparse 会将其替换为选项默认值的 str()。如果一个选项没有默认值(或者默认值为 None),%default 会扩展为 none

选项分组

当处理许多选项时,将这些选项分组以便更好地输出帮助信息是很方便的。一个 OptionParser 可以包含多个选项组,每个选项组又可以包含多个选项。

可以使用 OptionGroup 类来获取一个选项组。

class optparse.OptionGroup(parser, title, description=None)

其中:

  • parser 是要将该组插入的 OptionParser 实例。

  • title 是组的标题。

  • description(可选)是组的详细描述。

OptionGroup 继承自 OptionContainer(与 OptionParser 类似),因此可以使用 add_option() 方法向该组添加选项。

声明完所有选项后,可以使用 OptionParser 的方法 add_option_group() 将该组添加到先前定义的解析器中。

继续使用上一节中定义的解析器,将一个 OptionGroup 添加到解析器非常容易。

group = OptionGroup(parser, "Dangerous Options",
                    "Caution: use these options at your own risk.  "
                    "It is believed that some of them bite.")
group.add_option("-g", action="store_true", help="Group option.")
parser.add_option_group(group)

这将产生以下帮助输出:

Usage: <yourscript> [options] arg1 arg2

Options:
  -h, --help            show this help message and exit
  -v, --verbose         make lots of noise [default]
  -q, --quiet           be vewwy quiet (I'm hunting wabbits)
  -f FILE, --filename=FILE
                        write output to FILE
  -m MODE, --mode=MODE  interaction mode: novice, intermediate, or
                        expert [default: intermediate]

  Dangerous Options:
    Caution: use these options at your own risk.  It is believed that some
    of them bite.

    -g                  Group option.

一个更完整的示例可能涉及使用多个组:仍然扩展前面的示例。

group = OptionGroup(parser, "Dangerous Options",
                    "Caution: use these options at your own risk.  "
                    "It is believed that some of them bite.")
group.add_option("-g", action="store_true", help="Group option.")
parser.add_option_group(group)

group = OptionGroup(parser, "Debug Options")
group.add_option("-d", "--debug", action="store_true",
                 help="Print debug information")
group.add_option("-s", "--sql", action="store_true",
                 help="Print all SQL statements executed")
group.add_option("-e", action="store_true", help="Print every action done")
parser.add_option_group(group)

这将产生以下输出:

Usage: <yourscript> [options] arg1 arg2

Options:
  -h, --help            show this help message and exit
  -v, --verbose         make lots of noise [default]
  -q, --quiet           be vewwy quiet (I'm hunting wabbits)
  -f FILE, --filename=FILE
                        write output to FILE
  -m MODE, --mode=MODE  interaction mode: novice, intermediate, or expert
                        [default: intermediate]

  Dangerous Options:
    Caution: use these options at your own risk.  It is believed that some
    of them bite.

    -g                  Group option.

  Debug Options:
    -d, --debug         Print debug information
    -s, --sql           Print all SQL statements executed
    -e                  Print every action done

另一个有趣的方法,特别是在以编程方式处理选项组时,是:

OptionParser.get_option_group(opt_str)

返回短选项或长选项字符串 *opt_str* (例如 '-o''--option') 所属的 OptionGroup。如果没有这样的 OptionGroup,则返回 None

打印版本字符串

与简短的用法字符串类似,optparse 也可以为您的程序打印版本字符串。您必须将该字符串作为 version 参数传递给 OptionParser。

parser = OptionParser(usage="%prog [-f] [-q]", version="%prog 1.0")

%prog 的展开方式与在 usage 中相同。除此之外,version 可以包含您喜欢的任何内容。当您提供它时,optparse 会自动向您的解析器添加一个 --version 选项。如果在命令行上遇到此选项,它将展开您的 version 字符串(通过替换 %prog),将其打印到 stdout 并退出。

例如,如果您的脚本名为 /usr/bin/foo

$ /usr/bin/foo --version
foo 1.0

可以使用以下两个方法来打印和获取 version 字符串。

OptionParser.print_version(file=None)

将当前程序的版本消息 (self.version) 打印到 *file* (默认为 stdout)。与 print_usage() 一样,self.version 中任何出现的 %prog 都会被当前程序的名称替换。如果 self.version 为空或未定义,则不执行任何操作。

OptionParser.get_version()

print_version() 相同,但返回版本字符串而不是打印它。

optparse 如何处理错误

optparse 需要担心两种主要的错误类型:程序员错误和用户错误。程序员错误通常是对 OptionParser.add_option() 的错误调用,例如无效的选项字符串、未知的选项属性、缺少的选项属性等。这些错误通常以通常的方式处理:引发异常(optparse.OptionErrorTypeError),并让程序崩溃。

处理用户错误更为重要,因为无论您的代码多么稳定,都保证会发生这些错误。optparse 可以自动检测到一些用户错误,例如错误的选项参数(传递 -n 4x,而 -n 需要一个整数参数)、缺少参数(命令行末尾的 -n,而 -n 需要任何类型的参数)。此外,您可以调用 OptionParser.error() 来发出应用程序定义的错误情况的信号。

(options, args) = parser.parse_args()
...
if options.a and options.b:
    parser.error("options -a and -b are mutually exclusive")

在任何一种情况下,optparse 都会以相同的方式处理错误:它会将程序的用法消息和错误消息打印到标准错误,并以错误状态 2 退出。

考虑上面的第一个示例,其中用户向需要整数的选项传递了 4x

$ /usr/bin/foo -n 4x
Usage: foo [options]

foo: error: option -n: invalid integer value: '4x'

或者,用户根本没有传递值。

$ /usr/bin/foo -n
Usage: foo [options]

foo: error: -n option requires an argument

optparse 生成的错误消息始终会提及错误中涉及的选项;当从您的应用程序代码中调用 OptionParser.error() 时,请确保执行相同的操作。

如果 optparse 的默认错误处理行为不适合您的需求,您需要对 OptionParser 进行子类化,并覆盖其 exit() 和/或 error() 方法。

将它们放在一起

以下是基于 optparse 的脚本通常的样子。

from optparse import OptionParser
...
def main():
    usage = "usage: %prog [options] arg"
    parser = OptionParser(usage)
    parser.add_option("-f", "--file", dest="filename",
                      help="read data from FILENAME")
    parser.add_option("-v", "--verbose",
                      action="store_true", dest="verbose")
    parser.add_option("-q", "--quiet",
                      action="store_false", dest="verbose")
    ...
    (options, args) = parser.parse_args()
    if len(args) != 1:
        parser.error("incorrect number of arguments")
    if options.verbose:
        print("reading %s..." % options.filename)
    ...

if __name__ == "__main__":
    main()

参考指南

创建解析器

使用 optparse 的第一步是创建一个 OptionParser 实例。

class optparse.OptionParser(...)

OptionParser 构造函数没有必需的参数,但有许多可选的关键字参数。您应该始终将它们作为关键字参数传递,即不要依赖于参数声明的顺序。

usage (默认: "%prog [options]")

当您的程序运行不正确或带有 help 选项时要打印的用法摘要。当 optparse 打印用法字符串时,它会将 %prog 展开为 os.path.basename(sys.argv[0])(如果传递了该关键字参数,则展开为 prog)。要禁止用法消息,请传递特殊值 optparse.SUPPRESS_USAGE

option_list (默认: [])

用于填充解析器的 Option 对象列表。在 option_list 中的选项在 standard_option_list 中的任何选项(一个可能由 OptionParser 子类设置的类属性)之后,但在任何版本或 help 选项之前添加。已弃用;请在创建解析器后使用 add_option()

option_class (默认: optparse.Option)

add_option() 中向解析器添加选项时使用的类。

version (默认: None)

当用户提供版本选项时要打印的版本字符串。 如果您为 version 提供一个真值,optparse 将自动添加一个版本选项,其唯一选项字符串为 --version。子字符串 %prog 的扩展方式与 usage 相同。

conflict_handler (默认: "error")

指定当具有冲突选项字符串的选项添加到解析器时要执行的操作;请参阅 选项之间的冲突 部分。

description (默认: None)

一段文本,简要概述您的程序。optparse 将重新格式化此段落以适应当前终端宽度,并在用户请求帮助时打印(在 usage 之后,但在选项列表之前)。

formatter (默认: 一个新的 IndentedHelpFormatter)

一个 optparse.HelpFormatter 的实例,将用于打印帮助文本。optparse 为此目的提供了两个具体的类:IndentedHelpFormatter 和 TitledHelpFormatter。

add_help_option (默认: True)

如果为 true,optparse 将向解析器添加一个帮助选项(选项字符串为 -h--help)。

prog

usageversion 中扩展 %prog 时使用的字符串,而不是 os.path.basename(sys.argv[0])

epilog (默认: None)

在选项帮助之后打印的一段帮助文本。

填充解析器

有几种方法可以使用选项填充解析器。首选方法是使用 OptionParser.add_option(),如 教程 部分所示。add_option() 可以通过以下两种方式之一调用

  • 将 Option 实例(由 make_option() 返回)传递给它

  • 将任何组合的位置参数和关键字参数传递给它,这些参数是 make_option()(即 Option 构造函数)可以接受的,它将为您创建 Option 实例

另一种方法是将预先构建的 Option 实例列表传递给 OptionParser 构造函数,如下所示

option_list = [
    make_option("-f", "--filename",
                action="store", type="string", dest="filename"),
    make_option("-q", "--quiet",
                action="store_false", dest="verbose"),
    ]
parser = OptionParser(option_list=option_list)

(make_option() 是用于创建 Option 实例的工厂函数;目前它是 Option 构造函数的别名。未来版本的 optparse 可能会将 Option 分为几个类,而 make_option() 将选择要实例化的正确类。不要直接实例化 Option。)

定义选项

每个 Option 实例代表一组同义的命令行选项字符串,例如 -f--file。 您可以指定任意数量的短或长选项字符串,但您必须至少指定一个整体选项字符串。

创建 Option 实例的规范方法是使用 OptionParseradd_option() 方法。

OptionParser.add_option(option)
OptionParser.add_option(*opt_str, attr=value, ...)

要定义仅具有短选项字符串的选项

parser.add_option("-f", attr=value, ...)

要定义仅具有长选项字符串的选项

parser.add_option("--foo", attr=value, ...)

关键字参数定义新 Option 对象的属性。最重要的选项属性是 action,它在很大程度上决定了其他哪些属性是相关的或必需的。如果您传递不相关的选项属性,或未能传递必需的选项属性,optparse 将引发 OptionError 异常,解释您的错误。

选项的动作确定当 optparse 在命令行上遇到此选项时执行的操作。optparse 中硬编码的标准选项动作是

"store"

存储此选项的参数(默认)

"store_const"

存储一个常量值,通过 Option.const 预先设置

"store_true"

存储 True

"store_false"

存储 False

"append"

将此选项的参数附加到列表中

"append_const"

将一个常量值附加到列表中,通过 Option.const 预先设置

"count"

将计数器加一

"callback"

调用指定的函数

"help"

打印一条用法消息,包括所有选项及其文档

(如果您不提供动作,则默认值为 "store"。对于此动作,您还可以提供 typedest 选项属性;请参阅 标准选项动作。)

如您所见,大多数动作都涉及在某处存储或更新值。optparse 始终为此创建一个特殊的对象,通常称为 options,它是 optparse.Values 的实例。

class optparse.Values

一个对象,将已解析的参数名称和值作为属性保存。通常在调用 OptionParser.parse_args() 时创建,并且可以通过传递给 OptionParser.parse_args() 的 *values* 参数的自定义子类来覆盖(如 解析参数 中所述)。

选项参数(和各种其他值)根据 dest(目标)选项属性存储为此对象的属性。

例如,当您调用

parser.parse_args()

optparse 执行的第一件事之一是创建 options 对象

options = Values()

如果在此解析器中定义的选项之一是

parser.add_option("-f", "--file", action="store", type="string", dest="filename")

并且正在解析的命令行包含以下任何内容

-ffoo
-f foo
--file=foo
--file foo

然后,optparse 在看到此选项时,将执行相当于

options.filename = "foo"

typedest 选项属性几乎与 action 一样重要,但是 action 是对 *所有* 选项都有意义的唯一属性。

选项属性

class optparse.Option

一个单独的命令行参数,通过关键字传递给构造函数的各种属性。通常使用 OptionParser.add_option() 创建,而不是直接创建,并且可以通过传递给 OptionParseroption_class 参数由自定义类重写。

以下选项属性可以作为关键字参数传递给 OptionParser.add_option()。如果您传递的选项属性与特定选项不相关,或者未能传递必需的选项属性,optparse 将引发 OptionError 异常。

Option.action

(默认值:"store")

确定 optparse 在命令行上看到此选项时的行为;可用选项记录在此处

Option.type

(默认值:"string")

此选项期望的参数类型(例如,"string""int");可用的选项类型记录在此处

Option.dest

(默认值:从选项字符串派生)

如果选项的操作意味着在某个地方写入或修改值,则此属性告诉 optparse 将其写入何处:dest 命名 options 对象的属性,optparse 在解析命令行时构建该对象。

Option.default

如果命令行上未看到该选项,则用于此选项目标的默认值。另请参阅 OptionParser.set_defaults()

Option.nargs

(默认值:1)

当看到此选项时,应该消耗多少个 type 类型的参数。如果 > 1,optparse 将把值元组存储到 dest

Option.const

对于存储常量值的操作,要存储的常量值。

Option.choices

对于类型为 "choice" 的选项,用户可以选择的字符串列表。

Option.callback

对于操作为 "callback" 的选项,看到此选项时要调用的可调用对象。有关传递给可调用对象的参数的详细信息,请参阅 选项回调 部分。

Option.callback_args
Option.callback_kwargs

在四个标准回调参数之后传递给 callback 的其他位置和关键字参数。

Option.help

当用户提供 help 选项(例如 --help)后列出所有可用选项时,为此选项打印的帮助文本。 如果没有提供帮助文本,则将列出该选项,但不显示帮助文本。 要隐藏此选项,请使用特殊值 optparse.SUPPRESS_HELP

Option.metavar

(默认值:从选项字符串派生)

打印帮助文本时要使用的选项参数的替代符。 有关示例,请参见 教程 部分。

标准选项操作

各种选项操作的要求和效果略有不同。大多数操作都有一些相关的选项属性,您可以指定这些属性来指导 optparse 的行为;少数操作具有必需的属性,您必须为使用该操作的任何选项指定这些属性。

  • "store" [相关: type, dest, nargs, choices]

    该选项后面必须跟一个参数,该参数根据 type 转换为一个值,并存储在 dest 中。如果 nargs > 1,则将从命令行消耗多个参数;所有参数将根据 type 进行转换,并作为元组存储到 dest 中。请参阅标准选项类型部分。

    如果提供了 choices (字符串列表或元组),则类型默认为 "choice"

    如果未提供 type,则默认为 "string"

    如果未提供 dest,则 optparse 从第一个长选项字符串派生目标(例如,--foo-bar 意味着 foo_bar)。如果没有长选项字符串,则 optparse 从第一个短选项字符串派生目标(例如,-f 意味着 f)。

    示例

    parser.add_option("-f")
    parser.add_option("-p", type="float", nargs=3, dest="point")
    

    解析命令行时

    -f foo.txt -p 1 -3.5 4 -fbar.txt
    

    optparse 将设置

    options.f = "foo.txt"
    options.point = (1.0, -3.5, 4.0)
    options.f = "bar.txt"
    
  • "store_const" [必需:const;相关:dest]

    const 存储在 dest 中。

    示例

    parser.add_option("-q", "--quiet",
                      action="store_const", const=0, dest="verbose")
    parser.add_option("-v", "--verbose",
                      action="store_const", const=1, dest="verbose")
    parser.add_option("--noisy",
                      action="store_const", const=2, dest="verbose")
    

    如果看到 --noisyoptparse 将设置

    options.verbose = 2
    
  • "store_true" [相关:dest]

    "store_const" 的一个特殊情况,将 True 存储到 dest 中。

  • "store_false" [相关: dest]

    "store_true" 类似,但存储的是 False

    示例

    parser.add_option("--clobber", action="store_true", dest="clobber")
    parser.add_option("--no-clobber", action="store_false", dest="clobber")
    
  • "append" [相关: type, dest, nargs, choices]

    该选项后面必须跟一个参数,该参数将被附加到 dest 中的列表。如果未为 dest 提供默认值,则当 optparse 第一次在命令行上遇到此选项时,会自动创建一个空列表。 如果 nargs > 1,则会消耗多个参数,并将长度为 nargs 的元组附加到 dest

    typedest 的默认值与 "store" 操作的默认值相同。

    示例

    parser.add_option("-t", "--tracks", action="append", type="int")
    

    如果在命令行上看到 -t3optparse 将执行以下等效操作:

    options.tracks = []
    options.tracks.append(int("3"))
    

    如果稍后看到 --tracks=4,它会执行以下操作:

    options.tracks.append(int("4"))
    

    append 操作在选项的当前值上调用 append 方法。这意味着指定的任何默认值都必须具有 append 方法。这也意味着如果默认值不为空,则默认元素将出现在选项的已解析值中,并且来自命令行的任何值都将附加在这些默认值之后。

    >>> parser.add_option("--files", action="append", default=['~/.mypkg/defaults'])
    >>> opts, args = parser.parse_args(['--files', 'overrides.mypkg'])
    >>> opts.files
    ['~/.mypkg/defaults', 'overrides.mypkg']
    
  • "append_const" [必需: const; 相关: dest]

    "store_const" 类似,但值 const 会附加到 dest 中;与 "append" 一样,dest 默认为 None,并且在第一次遇到该选项时会自动创建一个空列表。

  • "count" [相关: dest]

    递增存储在 dest 的整数。如果未提供默认值,则 dest 会在第一次递增之前设置为零。

    示例

    parser.add_option("-v", action="count", dest="verbosity")
    

    第一次在命令行上看到 -v 时,optparse 将执行以下等效操作:

    options.verbosity = 0
    options.verbosity += 1
    

    每次后续出现 -v 都会导致:

    options.verbosity += 1
    
  • "callback" [必需: callback; 相关: type, nargs, callback_args, callback_kwargs]

    调用 callback 指定的函数,其调用方式如下:

    func(option, opt_str, value, parser, *args, **kwargs)
    

    有关更多详细信息,请参阅 选项回调 部分。

  • "help"

    为当前选项解析器中的所有选项打印完整的帮助消息。帮助消息由传递给 OptionParser 构造函数的 usage 字符串和传递给每个选项的 help 字符串构成。

    如果未为某个选项提供 help 字符串,它仍将列在帮助消息中。要完全省略某个选项,请使用特殊值 optparse.SUPPRESS_HELP

    optparse 会自动向所有 OptionParser 添加 help 选项,因此通常不需要创建该选项。

    示例

    from optparse import OptionParser, SUPPRESS_HELP
    
    # usually, a help option is added automatically, but that can
    # be suppressed using the add_help_option argument
    parser = OptionParser(add_help_option=False)
    
    parser.add_option("-h", "--help", action="help")
    parser.add_option("-v", action="store_true", dest="verbose",
                      help="Be moderately verbose")
    parser.add_option("--file", dest="filename",
                      help="Input file to read data from")
    parser.add_option("--secret", help=SUPPRESS_HELP)
    

    如果 optparse 在命令行上看到 -h--help,它将向 stdout 打印类似于以下帮助消息的内容(假设 sys.argv[0]"foo.py"

    Usage: foo.py [options]
    
    Options:
      -h, --help        Show this help message and exit
      -v                Be moderately verbose
      --file=FILENAME   Input file to read data from
    

    打印帮助消息后,optparse 将使用 sys.exit(0) 终止你的进程。

  • “版本”

    将提供给 OptionParser 的版本号打印到 stdout 并退出。版本号实际上由 OptionParser 的 print_version() 方法格式化和打印。通常仅在向 OptionParser 构造函数提供 version 参数时才相关。与 help 选项一样,你很少会创建 version 选项,因为 optparse 会在需要时自动添加它们。

标准选项类型

optparse 有五种内置的选项类型:"string""int""choice""float""complex"。如果需要添加新的选项类型,请参阅 扩展 optparse 部分。

字符串选项的参数不会以任何方式进行检查或转换:命令行上的文本按原样存储在目标中(或传递给回调)。

整数参数(类型为 "int")的解析方式如下:

  • 如果数字以 0x 开头,则将其解析为十六进制数字

  • 如果数字以 0 开头,则将其解析为八进制数字

  • 如果数字以 0b 开头,则将其解析为二进制数字

  • 否则,将数字解析为十进制数字

转换是通过调用具有适当基数(2、8、10 或 16)的 int() 完成的。如果此操作失败,optparse 也会失败,但会显示更有用的错误消息。

"float""complex" 选项参数会直接使用 float()complex() 进行转换,并采用类似的错误处理方式。

"choice" 选项是 "string" 选项的一个子类型。choices 选项属性(一个字符串序列)定义了允许的选项参数集合。 optparse.check_choice() 会将用户提供的选项参数与此主列表进行比较,如果提供了无效的字符串,则会引发 OptionValueError 异常。

解析参数

创建和填充 OptionParser 的全部意义在于调用其 parse_args() 方法。

OptionParser.parse_args(args=None, values=None)

解析在 args 中找到的命令行选项。

输入参数为

args

要处理的参数列表(默认值:sys.argv[1:]

values

一个 Values 对象,用于存储选项参数(默认值:Values 的新实例)– 如果您提供一个现有对象,选项默认值将不会在其上初始化

返回值是一对 (options, args),其中

options

与作为 values 传入的对象相同,或者是由 optparse 创建的 optparse.Values 实例

args

所有选项处理完毕后剩余的位置参数

最常见的用法是不提供任何关键字参数。如果您提供 values,它将通过重复调用 setattr() 进行修改(大致对于存储到选项目标中的每个选项参数调用一次),并由 parse_args() 返回。

如果 parse_args() 在参数列表中遇到任何错误,它会调用 OptionParser 的 error() 方法,并提供适当的最终用户错误消息。这最终会终止您的进程,并返回退出状态 2(传统的 Unix 命令行错误退出状态)。

查询和操作选项解析器

选项解析器的默认行为可以进行少量自定义,您也可以查看您的选项解析器,了解其中包含的内容。OptionParser 提供了几种方法来帮助您

OptionParser.disable_interspersed_args()

设置解析在第一个非选项处停止。例如,如果 -a-b 都是不带参数的简单选项,optparse 通常接受此语法

prog -a arg1 -b arg2

并将其视为等同于

prog -a -b arg1 arg2

要禁用此功能,请调用 disable_interspersed_args()。这将恢复传统的 Unix 语法,其中选项解析在第一个非选项参数处停止。

如果您的命令处理器运行另一个具有自身选项的命令,并且您想确保这些选项不会混淆,请使用此方法。例如,每个命令可能具有不同的选项集。

OptionParser.enable_interspersed_args()

设置解析在第一个非选项处不停止,允许将开关与命令参数交错。这是默认行为。

OptionParser.get_option(opt_str)

返回具有选项字符串 opt_str 的 Option 实例,如果没有具有该选项字符串的选项,则返回 None

OptionParser.has_option(opt_str)

如果 OptionParser 具有带有选项字符串 opt_str 的选项(例如,-q--verbose),则返回 True

OptionParser.remove_option(opt_str)

如果 OptionParser 具有与 opt_str 对应的选项,则会删除该选项。如果该选项提供了任何其他选项字符串,则所有这些选项字符串都会变为无效。如果 opt_str 未出现在属于此 OptionParser 的任何选项中,则会引发 ValueError 异常。

选项之间的冲突

如果您不小心,很容易定义具有冲突选项字符串的选项

parser.add_option("-n", "--dry-run", ...)
...
parser.add_option("-n", "--noisy", ...)

(如果您定义了自己的具有某些标准选项的 OptionParser 子类,则尤其如此。)

每次添加选项时,optparse 都会检查与现有选项的冲突。如果发现任何冲突,它会调用当前的冲突处理机制。您可以在构造函数中设置冲突处理机制

parser = OptionParser(..., conflict_handler=handler)

或者通过单独的调用

parser.set_conflict_handler(handler)

可用的冲突处理程序是

"error"(默认)

假设选项冲突是编程错误,并引发 OptionConflictError 异常

"resolve"

智能地解决选项冲突(请参阅下文)

例如,让我们定义一个 OptionParser,它可以智能地解决冲突,并向其中添加冲突选项

parser = OptionParser(conflict_handler="resolve")
parser.add_option("-n", "--dry-run", ..., help="do no harm")
parser.add_option("-n", "--noisy", ..., help="be noisy")

此时,optparse 检测到先前添加的选项已在使用 -n 选项字符串。由于 conflict_handler"resolve",因此它通过从早期选项的选项字符串列表中删除 -n 来解决这种情况。现在,--dry-run 是用户激活该选项的唯一方法。如果用户请求帮助,帮助消息将反映这一点

Options:
  --dry-run     do no harm
  ...
  -n, --noisy   be noisy

可以逐渐删除先前添加的选项的选项字符串,直到没有剩余的选项字符串,并且用户无法从命令行调用该选项。在这种情况下,optparse 会完全删除该选项,因此它不会显示在帮助文本或任何其他位置。继续使用我们现有的 OptionParser

parser.add_option("--dry-run", ..., help="new dry-run option")

此时,原始的 -n/--dry-run 选项不再可访问,因此 optparse 会将其删除,留下此帮助文本

Options:
  ...
  -n, --noisy   be noisy
  --dry-run     new dry-run option

清理

OptionParser 实例有几个循环引用。这对于 Python 的垃圾回收器来说不应该是一个问题,但是您可能希望通过在完成 OptionParser 后调用 destroy() 来显式地断开循环引用。这在长运行的应用程序中特别有用,在这些应用程序中,大型对象图可以从您的 OptionParser 访问。

其他方法

OptionParser 支持其他几种公共方法

OptionParser.set_usage(usage)

根据上面为 usage 构造函数关键字参数描述的规则设置 usage 字符串。传递 None 会设置默认 usage 字符串;使用 optparse.SUPPRESS_USAGE 来抑制 usage 消息。

OptionParser.print_usage(file=None)

将当前程序的使用信息(self.usage)打印到文件(默认为 stdout)。在 self.usage 中出现的任何字符串 %prog 都会被替换为当前程序的名称。如果 self.usage 为空或未定义,则不执行任何操作。

OptionParser.get_usage()

print_usage() 相同,但返回使用字符串而不是打印它。

OptionParser.set_defaults(dest=value, ...)

一次为多个选项目标设置默认值。使用 set_defaults() 是设置选项默认值的首选方法,因为多个选项可以共享同一个目标。例如,如果多个“模式”选项都设置相同的目标,则其中任何一个都可以设置默认值,并且最后一个会生效。

parser.add_option("--advanced", action="store_const",
                  dest="mode", const="advanced",
                  default="novice")    # overridden below
parser.add_option("--novice", action="store_const",
                  dest="mode", const="novice",
                  default="advanced")  # overrides above setting

为了避免这种混乱,请使用 set_defaults()

parser.set_defaults(mode="advanced")
parser.add_option("--advanced", action="store_const",
                  dest="mode", const="advanced")
parser.add_option("--novice", action="store_const",
                  dest="mode", const="novice")

选项回调

optparse 的内置动作和类型不足以满足您的需求时,您有两个选择:扩展 optparse 或定义一个回调选项。扩展 optparse 更通用,但对于许多简单的情况来说是多余的。通常,一个简单的回调就足够了。

定义回调选项有两个步骤

  • 使用 "callback" 动作定义选项本身

  • 编写回调;这是一个函数(或方法),它至少接受四个参数,如下所述

定义回调选项

与往常一样,定义回调选项的最简单方法是使用 OptionParser.add_option() 方法。除了 action 之外,您必须指定的唯一选项属性是 callback,即要调用的函数。

parser.add_option("-c", action="callback", callback=my_callback)

callback 是一个函数(或其他可调用对象),因此在创建此回调选项时,您必须已经定义了 my_callback()。在这个简单的例子中,optparse 甚至不知道 -c 是否接受任何参数,这通常意味着该选项不接受任何参数—命令行上仅仅存在 -c 就足够了。但在某些情况下,您可能希望您的回调使用任意数量的命令行参数。这就是编写回调变得棘手的地方;本节稍后将介绍它。

optparse 总是将四个特定的参数传递给您的回调,并且只有在您通过 callback_argscallback_kwargs 指定它们时,它才会传递额外的参数。因此,最小的回调函数签名是

def my_callback(option, opt, value, parser):

下面描述了回调的四个参数。

在定义回调选项时,您还可以提供其他几个选项属性

type

具有通常的含义:与 "store""append" 动作一样,它指示 optparse 使用一个参数并将其转换为 type。但是,optparse 不是将转换后的值存储在任何地方,而是将其传递给您的回调函数。

nargs

也具有其通常的含义:如果提供且 > 1,则 optparse 将使用 nargs 个参数,每个参数都必须可转换为 type。然后,它将转换后的值元组传递给您的回调。

callback_args

要传递给回调的额外位置参数的元组

callback_kwargs

要传递给回调的额外关键字参数的字典

如何调用回调

所有回调都按如下方式调用

func(option, opt_str, value, parser, *args, **kwargs)

其中:

选项

是调用回调的 Option 实例

opt_str

是在命令行上看到的触发回调的选项字符串。(如果使用了缩写的长选项,opt_str 将是完整的、规范的选项字符串—例如,如果用户在命令行上输入 --foo 作为 --foobar 的缩写,则 opt_str 将是 "--foobar"。)

value

是在命令行上看到的此选项的参数。optparse 仅在设置了 type 时才会期望参数;value 的类型将是选项类型所暗示的类型。如果此选项的 typeNone(不期望参数),则 value 将为 None。如果 nargs > 1,则 value 将是适当类型的值元组。

parser

是驱动整个过程的 OptionParser 实例,主要是因为它可以通过其实例属性访问其他一些有趣的数据

parser.largs

当前剩余参数列表,即已被消耗但既不是选项也不是选项参数的参数。请随意修改 parser.largs,例如,向其中添加更多参数。(此列表将成为 args,即 parse_args() 的第二个返回值。)

parser.rargs

当前剩余参数列表,即删除 opt_strvalue(如果适用)之后,并且只有它们之后的参数仍然存在。请随意修改 parser.rargs,例如,通过使用更多参数。

parser.values

默认情况下存储选项值的对象(optparse.OptionValues 的实例)。这允许回调使用与 optparse 的其余部分相同的机制来存储选项值;您无需使用全局变量或闭包。您还可以访问或修改命令行上已遇到的任何选项的值。

args

是通过 callback_args 选项属性提供的任意位置参数的元组。

kwargs

是通过 callback_kwargs 提供的任意关键字参数的字典。

在回调中引发错误

如果选项或其参数存在任何问题,回调函数应引发 OptionValueError 异常。optparse 会捕获此异常并终止程序,并将您提供的错误消息打印到 stderr。您的消息应该清晰、简洁、准确,并提及出错的选项。否则,用户将很难弄清楚他们做错了什么。

回调示例 1:简单的回调

这是一个回调选项的示例,它不带任何参数,仅记录该选项已被看到

def record_foo_seen(option, opt_str, value, parser):
    parser.values.saw_foo = True

parser.add_option("--foo", action="callback", callback=record_foo_seen)

当然,您可以使用 "store_true" 动作来实现此目的。

回调示例 2:检查选项顺序

这是一个稍微有趣一点的示例:记录 -a 被看到的事实,但如果它在命令行中出现在 -b 之后,则会崩溃。

def check_order(option, opt_str, value, parser):
    if parser.values.b:
        raise OptionValueError("can't use -a after -b")
    parser.values.a = 1
...
parser.add_option("-a", action="callback", callback=check_order)
parser.add_option("-b", action="store_true", dest="b")

回调示例 3:检查选项顺序(通用化)

如果您想为几个类似的选项重用此回调(设置标志,但如果 -b 已经被看到则崩溃),则需要做一些工作:错误消息和它设置的标志必须通用化。

def check_order(option, opt_str, value, parser):
    if parser.values.b:
        raise OptionValueError("can't use %s after -b" % opt_str)
    setattr(parser.values, option.dest, 1)
...
parser.add_option("-a", action="callback", callback=check_order, dest='a')
parser.add_option("-b", action="store_true", dest="b")
parser.add_option("-c", action="callback", callback=check_order, dest='c')

回调示例 4:检查任意条件

当然,您可以在其中放置任何条件,而不仅仅是检查已经定义的选项的值。例如,如果您有不应在满月时调用的选项,您只需这样做

def check_moon(option, opt_str, value, parser):
    if is_moon_full():
        raise OptionValueError("%s option invalid when moon is full"
                               % opt_str)
    setattr(parser.values, option.dest, 1)
...
parser.add_option("--foo",
                  action="callback", callback=check_moon, dest="foo")

is_moon_full() 的定义留给读者作为练习。)

回调示例 5:固定参数

当您定义接受固定数量参数的回调选项时,事情会变得稍微有趣一些。指定回调选项接受参数类似于定义 "store""append" 选项:如果定义 type,则该选项接受一个参数,该参数必须可以转换为该类型;如果您进一步定义 nargs,则该选项接受 nargs 个参数。

这是一个仅模拟标准 "store" 动作的示例

def store_value(option, opt_str, value, parser):
    setattr(parser.values, option.dest, value)
...
parser.add_option("--foo",
                  action="callback", callback=store_value,
                  type="int", nargs=3, dest="foo")

请注意,optparse 负责为您消耗 3 个参数并将它们转换为整数;您只需要存储它们即可。(或者其他任何操作;显然,此示例不需要回调。)

回调示例 6:可变参数

当您希望选项接受可变数量的参数时,事情会变得复杂。对于这种情况,您必须编写一个回调,因为 optparse 不提供任何内置功能。并且您必须处理 optparse 通常为您处理的传统 Unix 命令行解析的某些复杂性。特别是,回调应实现裸 --- 参数的传统规则

  • --- 可以是选项参数

  • -- (如果不是某个选项的参数):停止命令行处理并丢弃 --

  • - (如果不是某个选项的参数):停止命令行处理但保留 -(将其附加到 parser.largs

如果您想要一个接受可变数量参数的选项,则有几个微妙的、棘手的问题需要担心。您选择的确切实现将基于您愿意为应用程序做出的权衡(这就是为什么 optparse 不直接支持这种类型的东西)。

不过,这里有一个针对具有可变参数的选项的回调的尝试

def vararg_callback(option, opt_str, value, parser):
    assert value is None
    value = []

    def floatable(str):
        try:
            float(str)
            return True
        except ValueError:
            return False

    for arg in parser.rargs:
        # stop on --foo like options
        if arg[:2] == "--" and len(arg) > 2:
            break
        # stop on -a, but not on -3 or -3.0
        if arg[:1] == "-" and len(arg) > 1 and not floatable(arg):
            break
        value.append(arg)

    del parser.rargs[:len(value)]
    setattr(parser.values, option.dest, value)

...
parser.add_option("-c", "--callback", dest="vararg_attr",
                  action="callback", callback=vararg_callback)

扩展 optparse

由于 optparse 如何解释命令行选项的两个主要控制因素是每个选项的动作和类型,因此最可能的扩展方向是添加新的动作和新的类型。

添加新类型

要添加新类型,您需要定义 optparseOption 类的自定义子类。此类具有几个属性,这些属性定义了 optparse 的类型:TYPESTYPE_CHECKER

Option.TYPES

类型名称的元组;在您的子类中,只需定义一个新的元组 TYPES,该元组建立在标准元组的基础上。

Option.TYPE_CHECKER

一个将类型名称映射到类型检查函数的字典。类型检查函数具有以下签名

def check_mytype(option, opt, value)

其中 option 是一个 Option 实例,opt 是一个选项字符串(例如,-f),而 value 是来自命令行、必须检查并转换为您所需的类型的字符串。check_mytype() 应返回假设类型 mytype 的对象。类型检查函数返回的值将最终出现在 OptionParser.parse_args() 返回的 OptionValues 实例中,或作为 value 参数传递给回调。

如果您的类型检查函数遇到任何问题,则应引发 OptionValueError 异常。OptionValueError 接受一个字符串参数,该参数按原样传递给 OptionParsererror() 方法,该方法依次前置程序名称和字符串 "error:",并将所有内容打印到 stderr,然后终止进程。

这是一个简单的示例,演示如何添加 "complex" 选项类型以在命令行上解析 Python 风格的复数。(这甚至比以前更傻了,因为 optparse 1.3 添加了对复数的内置支持,但没关系。)

首先,必要的导入

from copy import copy
from optparse import Option, OptionValueError

您需要首先定义类型检查器,因为它稍后会被引用(在您的 Option 子类的 TYPE_CHECKER 类属性中)

def check_complex(option, opt, value):
    try:
        return complex(value)
    except ValueError:
        raise OptionValueError(
            "option %s: invalid complex value: %r" % (opt, value))

最后,Option 子类

class MyOption (Option):
    TYPES = Option.TYPES + ("complex",)
    TYPE_CHECKER = copy(Option.TYPE_CHECKER)
    TYPE_CHECKER["complex"] = check_complex

(如果我们没有 copy() Option.TYPE_CHECKER,我们将最终修改 optparse 的 Option 类的 TYPE_CHECKER 属性。由于这是 Python,除了良好的礼仪和常识之外,没有任何东西能阻止您这样做。)

就这样!现在,您可以编写一个脚本,该脚本像任何其他基于 optparse 的脚本一样使用新的选项类型,只是您必须指示 OptionParser 使用 MyOption 而不是 Option

parser = OptionParser(option_class=MyOption)
parser.add_option("-c", type="complex")

或者,您可以构建自己的选项列表并将其传递给 OptionParser;如果您不以上述方式使用 add_option(),则无需告知 OptionParser 使用哪个选项类

option_list = [MyOption("-c", action="store", type="complex", dest="c")]
parser = OptionParser(option_list=option_list)

添加新动作

添加新的动作会稍微复杂一些,因为您需要理解 optparse 对动作有几种分类。

“存储”动作

导致 optparse 将值存储到当前 OptionValues 实例的属性中的动作;这些选项需要在 Option 构造函数中提供 dest 属性。

“类型化”动作

从命令行获取值并期望它是特定类型的动作;或者更确切地说,是可以转换为特定类型的字符串。这些选项需要在 Option 构造函数中提供 type 属性。

这些是重叠的集合:一些默认的“存储”动作是 "store""store_const""append""count",而默认的“类型化”动作是 "store""append""callback"

当您添加一个动作时,您需要通过将其列在 Option 的以下至少一个类属性中来对其进行分类(所有类属性都是字符串列表)

Option.ACTIONS

所有动作都必须列在 ACTIONS 中。

Option.STORE_ACTIONS

“存储”动作会额外列在此处。

Option.TYPED_ACTIONS

“类型化”动作会额外列在此处。

Option.ALWAYS_TYPED_ACTIONS

始终需要类型的动作(即其选项始终需要值的动作)会额外列在此处。这唯一的作用是 optparse 将默认类型 "string" 分配给那些没有显式类型且其动作在 ALWAYS_TYPED_ACTIONS 中列出的选项。

为了真正实现您的新动作,您必须重写 Option 的 take_action() 方法,并添加一个可以识别您的动作的情况。

例如,让我们添加一个 "extend" 动作。这类似于标准的 "append" 动作,但是 "extend" 不是从命令行获取单个值并将其附加到现有列表中,而是会获取以逗号分隔的字符串中的多个值,并用它们扩展现有列表。也就是说,如果 --names 是一个 "extend" 类型的 "string" 选项,则命令行

--names=foo,bar --names blah --names ding,dong

将产生一个列表

["foo", "bar", "blah", "ding", "dong"]

再次定义 Option 的子类

class MyOption(Option):

    ACTIONS = Option.ACTIONS + ("extend",)
    STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
    TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
    ALWAYS_TYPED_ACTIONS = Option.ALWAYS_TYPED_ACTIONS + ("extend",)

    def take_action(self, action, dest, opt, value, values, parser):
        if action == "extend":
            lvalue = value.split(",")
            values.ensure_value(dest, []).extend(lvalue)
        else:
            Option.take_action(
                self, action, dest, opt, value, values, parser)

值得注意的特点

  • "extend" 既期望命令行上的值,又在某处存储该值,因此它同时进入 STORE_ACTIONSTYPED_ACTIONS

  • 为了确保 optparse 将默认类型 "string" 分配给 "extend" 动作,我们将 "extend" 动作也放在 ALWAYS_TYPED_ACTIONS 中。

  • MyOption.take_action() 仅实现这一个新动作,并将控制权传递回 Option.take_action() 以进行标准的 optparse 动作。

  • values 是 optparse_parser.Values 类的实例,它提供了非常有用的 ensure_value() 方法。ensure_value() 本质上是带有安全阀的 getattr();它被调用为

    values.ensure_value(attr, value)
    

    如果 valuesattr 属性不存在或为 None,则 ensure_value() 首先将其设置为 value,然后返回 value。这对于诸如 "extend""append""count" 之类的动作非常方便,它们都在变量中累积数据,并期望该变量为特定类型(前两个为列表,后者为整数)。使用 ensure_value() 意味着使用您的动作的脚本无需担心为相关选项目标设置默认值;它们可以将默认值保留为 None,而 ensure_value() 会在需要时负责使其正确。

异常

exception optparse.OptionError

如果创建的 Option 实例包含无效或不一致的参数,则会引发此异常。

exception optparse.OptionConflictError

如果将冲突的选项添加到 OptionParser,则会引发此异常。

exception optparse.OptionValueError

如果在命令行中遇到无效的选项值,则会引发此异常。

exception optparse.BadOptionError

如果在命令行中传递了无效的选项,则会引发此异常。

exception optparse.AmbiguousOptionError

如果在命令行中传递了模棱两可的选项,则会引发此异常。