Skip to main content

36.1. optparse —用于命令行选项的解析器

源代码: Lib/optparse.py

3.2 版后已移除: optparse 模块已弃用,不会进一步开发;开发将继续与 argparse 模块。


与旧的 getopt 模块相比,optparse 是一个更方便,灵活和强大的用于解析命令行选项的库。 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])。

36.1.1. 背景

optparse 被明确设计为鼓励使用简单,常规的命令行界面创建程序。为此,它仅支持在Unix下常规使用的最常见的命令行语法和语义。如果您不熟悉这些约定,请阅读本部分以熟悉它们。

36.1.1.1. 术语

论据

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

偶尔需要替换除 sys.argv[1:] 之外的参数列表,因此您应该将“参数”解释为“ sys.argv[1:] 的元素或作为 sys.argv[1:] 的替代提供的一些其他列表”。

选项

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

世界上看到的一些其他选项语法包括:

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

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

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

  • 一个斜线后跟一个字母,或几个字母,或一个字,例如。 /f/file

optparse 不支持这些选项语法,它们从不会。这是故意的:前三个是任何环境下的非标准,如果你专门针对VMS,MS-DOS和/或Windows,最后一个是有意义的。

选项参数

在选项后面的参数与该选项紧密相关,并且当该选项为时,从参数列表中消耗。使用 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 是位置参数。

36.1.1.2. 什么是选项?

选项用于提供额外的信息来调整或定制程序的执行。如果不清楚,选项通常是 optional。一个程序应该能够运行很好,没有任何选择。 (从Unix或GNU工具集中选择一个随机程序,它可以运行没有任何选项,仍然有意义吗?主要的例外是 findtardd —所有这些都是被正确批评的突变奇怪因为它们的非标准语法和混乱的界面。)

许多人希望他们的计划有“必要的选择”。想想吧。如果需要,那么它是 不可选!如果有一个信息,你的程序绝对需要为了成功运行,这是位置参数是什么。

作为良好的命令行界面设计的示例,考虑用于复制文件的谦逊的 cp 实用程序。尝试复制文件而不提供目标和至少一个源没有什么意义。因此,如果你运行它没有参数,cp 失败。但是,它有一个灵活,有用的语法,不需要任何选项:

cp SOURCE DEST
cp SOURCE ... DEST-DIR

你可以得到很远的只是那个。大多数 cp 实现提供了一系列选项来精确地调整文件的复制方式:您可以保留模式和修改时间,避免遵循符号链接,在删除现有文件之前询问等。但是这些都不会分散 cp 的核心使命是将一个文件复制到另一个文件,或将几个文件复制到另一个目录。

36.1.1.3. 什么是位置参数?

位置参数是你的程序绝对,积极地要求运行的那些信息。

良好的用户界面应该具有尽可能少的绝对要求。如果你的程序需要17个不同的信息以便成功运行,how 就不需要从用户那里得到信息 - 大多数人会在成功运行程序之前放弃和离开。无论用户界面是命令行,配置文件还是GUI,这都适用:如果您对用户提出了很多要求,他们大多数都会放弃。

简而言之,尽量减少用户绝对需要提供的信息量 - 尽可能使用明智的默认值。当然,你也想让你的程序相当灵活。这是什么选项。同样,如果它们是配置文件中的条目,GUI的“首选项”对话框中的窗口小部件或命令行选项,则实现的选项越多,程序越灵活,更复杂的实现变得。太多的灵活性也有缺点,当然;太多的选项可能会淹没用户,使您的代码更难以维护。

36.1.2. 教程

虽然 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 是最基本的。

36.1.2.1. 了解选项操作

操作告诉 optparse 在命令行遇到选项时该怎么做。有一组固定的动作硬编码为 optparse;添加新操作是 扩展 optparse 部分中所述的高级主题。大多数操作告诉 optparse 在某些变量中存储一个值 - 例如,从命令行取一个字符串并将其存储在 options 的属性中。

如果不指定选项操作,则 optparse 默认为 store

36.1.2.2. 商店行动

最常见的选项操作是 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")

如果您没有提供目的地,optparse 会从选项字符串中找出明智的默认值:如果第一个长选项字符串是 --foo-bar,则默认目标是 foo_bar。如果没有长选项字符串,optparse 查看第一个短选项字符串:-f 的默认目标是 f

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

36.1.2.3. 处理布尔(标志)选项

标志选项—将变量设置为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")

这里我们有两个不同的选项与相同的目的地,这是完全OK。 (这只是意味着你必须在设置默认值时有点小心 - 见下文。)

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

36.1.2.4. 其他行为

optparse 支持的其他一些操作包括:

"store_const"

存储恒定值

"append"

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

"count"

将计数器递增1

"callback"

调用指定的函数

这些内容包括在 参考指南,参考指南和 选项回调 部分。

36.1.2.5. 默认值

所有上述示例涉及在看到某些命令行选项时设置一些变量(“目标”)。如果这些选项从未见过,会发生什么?由于我们没有提供任何默认值,它们都设置为 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")

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

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()

与之前一样,为给定选项目标指定的最后一个值是计数的值。为了清楚起见,尝试使用一种方法或另一种方法设置默认值,而不是两者。

36.1.2.6. 生成帮助

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 使用一个平淡但明智的默认值:"Usage: %prog [options]",这是很好,如果你的脚本不采取任何位置参数。

  • 每个选项定义一个帮助字符串,不必担心换行— optparse 负责包装行和帮助输出看起来不错。

  • 采用值的选项在自动生成的帮助消息中指示此事实,例如为“模式”选项:

    -m MODE, --mode=MODE
    

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

    -f FILE, --filename=FILE
    

    这对于不仅仅节省空间是重要的:手动编写的帮助文本使用元变量 FILE 来引导用户,因为在半形式语法 -f FILE 和非正式语义描述“写输出到FILE”之间存在连接, 。这是一个简单但有效的方法,使您的帮助文本更清晰,更有用的最终用户。

  • 具有默认值的选项可以在帮助字符串中包括 %defaultoptparse 将用该选项的默认值的 str() 替换。如果选项没有默认值(或默认值为 None),%default 将扩展为 none

36.1.2.6.1. 分组选项

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

使用 OptionGroup 类获取选项组:

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

哪里

  • 解析器是 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

36.1.2.7. 打印版本字符串

与简短的使用字符串类似,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() 相同,但返回版本字符串,而不是打印它。

36.1.2.8. 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() 方法。

36.1.2.9. 把它放在一起

这里是基于 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()

36.1.3. 参考指南

36.1.3.1. 创建解析器

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

class optparse.OptionParser(...)

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

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

当程序运行不正确或使用帮助选项时打印的使用摘要。当 optparse 打印使用字符串时,它将 %prog 扩展为 os.path.basename(sys.argv[0]) (如果您通过了该关键字参数,则将其扩展为 prog)。要抑制使用消息,请传递特殊值 optparse.SUPPRESS_USAGE

option_list (默认值:[]

用于用解析器填充的Option对象的列表。 option_list 中的选项在 standard_option_list 中的任何选项(可以由OptionParser子类设置的类属性)之后,但在任何版本或帮助选项之前添加。已弃用;而是在创建解析器之后使用 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 中替换 os.path.basename(sys.argv[0]) 扩展 %prog 时使用的字符串。

epilog (默认值:None

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

36.1.3.2. 填充解析器

有几种方法来使用选项填充解析器。首选方法是使用 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() 将选择正确的类来实例化,不要直接实例化)

36.1.3.3. 定义选项

每个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 异常来解释您的错误。

选项的 action 确定在命令行遇到此选项时 optparse 会做什么。硬编码到 optparse 中的标准选项操作有:

"store"

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

"store_const"

存储恒定值

"store_true"

存储真实值

"store_false"

存储假值

"append"

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

"append_const"

将常量值附加到列表

"count"

将计数器递增1

"callback"

调用指定的函数

"help"

打印包含所有选项和文档的使用消息

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

如你所见,大多数操作涉及在某处存储或更新值。 optparse 总是为此创建一个特殊对象,通常称为 options (它恰好是 optparse.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 是唯一对 all 选项有意义的选项。

36.1.3.4. 选项属性

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

Option.action

(默认值:"store"

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

Option.type

(默认值:"string"

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

Option.dest

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

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

Option.default

如果在命令行中未显示该选项,则用于此选项目标的值。参见 OptionParser.set_defaults()

Option.nargs

(默认值:1)

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

Option.const

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

Option.choices

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

Option.callback

对于具有操作 "callback" 的选项,当看到此选项时调用callable。有关传递给可调用对象的参数的详细信息,请参见 选项回调 节。

Option.callback_args
Option.callback_kwargs

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

Option.help

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

Option.metavar

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

打印帮助文本时要使用的选项参数。参见 教程 部分的例子。

36.1.3.5. 标准选项操作

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

  • "store" [相关:typedestnargschoices]

    该选项后面必须跟有参数,该参数将根据 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" 的一个特例,它将真实值存储到 dest 中。

  • "store_false" [相关:dest]

    "store_true",但存储一个假值。

    例:

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

    该选项后面必须是一个参数,该参数附加到 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")
    

    第一次在命令行上看到 -voptparse 等价于:

    options.verbosity = 0
    options.verbosity += 1
    

    每次后来发生的 -v 结果

    options.verbosity += 1
    
  • "callback" [必需:callback;相关:typenargscallback_argscallback_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) 终止您的进程。

  • "version"

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

36.1.3.6. 标准选项类型

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

36.1.3.7. 解析参数

创建和填充OptionParser的整个要点是调用它的 parse_args() 方法:

(options, args) = parser.parse_args(args=None, values=None)

其中输入参数为

args

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

values

一个用于存储选项参数(默认:Values 的一个新实例)的 optparse.Values 对象 - 如果给定一个现有对象,则不会初始化选项defaults

和返回值是

options

values 传递的相同对象或由 optparse 创建的optparse.Values实例

args

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

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

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

36.1.3.8. 查询和操作您的选项解析器

选项解析器的默认行为可以稍微自定义,你也可以勾选你的选项解析器,看看有什么。 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

36.1.3.9. 选项之间的冲突

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

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

36.1.3.10. 清理

OptionParser实例具有多个循环引用。这不应该是Python的垃圾收集器的问题,但你可能希望打破循环引用显式地通过调用 destroy() 在您的OptionParser一旦你完成它。这在长期运行的应用程序中特别有用,其中可以从OptionParser访问大对象图。

36.1.3.11. 其他方法

OptionParser支持几种其他公共方法:

OptionParser.set_usage(usage)

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

OptionParser.print_usage(file=None)

将当前程序(self.usage)的使用消息打印到 file (默认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")

36.1.4. 选项回调

optparse 的内置操作和类型不足以满足您的需要时,您有两个选择:扩展 optparse 或定义回调选项。扩展 optparse 更一般,但对于很多简单的情况过度杀伤。通常一个简单的回调是你需要的。

定义回调选项有两个步骤:

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

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

36.1.4.1. 定义回调选项

和往常一样,定义回调选项的最简单的方法是使用 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

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

36.1.4.2. 如何调用回调

所有回调的调用如下:

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

哪里

option

是调用回调的Option实例

opt_str

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

value

是在命令行上看到的此选项的参数。如果 type 被设置,optparse 只需要一个参数; value 的类型将是选项类型所暗示的类型。如果此选项的 typeNone (不需要参数),则 value 将是 None。如果 nargs> 1,则 value 将是适当类型的值的元组。

parser

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

parser.largs

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

parser.rargs

剩余参数的当前列表,即。与 opt_strvalue (如果适用)删除,只有后面的参数仍然存在。随意修改 parser.rargs,例如通过消耗更多的参数。

parser.values

缺省存储选项值的对象(optparse.OptionValues的一个实例)。这允许回调使用与 optparse 的其余部分相同的机制来存储选项值;你不需要搞砸全局或闭包。您还可以访问或修改命令行中已遇到的任何选项的值。

args

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

kwargs

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

36.1.4.3. 在回调中引发错误

如果选项或其参数有任何问题,回调函数应该引发 OptionValueErroroptparse 捕获并终止程序,打印您提供给stderr的错误消息。您的信息应该清晰,简洁,准确,并提及错误的选项。否则,用户将很难知道他做错了什么。

36.1.4.4. 回调示例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" 的行动。

36.1.4.5. 回调示例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")

36.1.4.6. 回调示例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')

36.1.4.7. 回调示例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() 的定义留作读者的练习。)

36.1.4.8. 回调示例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个参数并将它们转换为整数;所有你需要做的是存储它们。 (或者什么;显然你不需要回调这个例子。)

36.1.4.9. 回调示例6:变量参数

当你想要一个选项采取可变数量的参数时,事情变得毛茸茸。对于这种情况,您必须编写回调,因为 optparse 不为其提供任何内置功能。你必须处理 optparse 通常为你处理的常规Unix命令行解析的某些复杂性。特别是,回调应该实现裸 --- 参数的常规规则:

  • --- 可以是选项参数

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

  • - (如果不是某些选项的参数):halt命令行处理,但保留 - (将其附加到 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)

36.1.5. 扩展 optparse

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

36.1.5.1. 添加新类型

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

Option.TYPES

一个类型名称的元组;在你的子类中,简单地定义一个基于标准的新的元组 TYPES

Option.TYPE_CHECKER

字典映射类型名称到类型检查函数。类型检查功能具有以下签名:

def check_mytype(option, opt, value)

其中 optionOption 实例,opt 是选项字符串(例如,-f),value 是必须检查并转换为所需类型的命令行字符串。 check_mytype() 应该返回假设类型 mytype 的对象。类型检查函数返回的值将在由 OptionParser.parse_args() 返回的OptionValues实例中结束,或作为 value 参数传递到回调。

如果遇到任何问题,您的类型检查功能应提高 OptionValueErrorOptionValueError 接受一个字符串参数,它按原样传递给 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

(如果我们没有使用 Option.TYPE_CHECKERcopy(),我们最终会修改 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)

36.1.5.2. 添加新操作

添加新动作有点棘手,因为你必须明白 optparse 有几个动作的分类:

“存储”操作

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

“打字”动作

从命令行获取值并期望它具有某种类型的动作;或者,可以转换为某种类型的字符串。这些选项需要 type 属性到Option构造函数。

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

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

Option.ACTIONS

所有操作都必须在ACTIONS中列出。

Option.STORE_ACTIONS

“存储”操作在此处另外列出。

Option.TYPED_ACTIONS

“typed”动作在这里另外列出。

Option.ALWAYS_TYPED_ACTIONS

此处还列出了始终采用类型(即其选项始终采用值)的操作。其唯一的效果是,optparse 将默认类型 "string" 分配给没有显式类型的选项,其操作在 ALWAYS_TYPED_ACTIONS 中列出。

为了实际实现您的新操作,您必须重写Option的 take_action() 方法,并添加一个识别您的操作的案例。

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

--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() 意味着使用您的操作的脚本不必担心为有问题的选项目标设置默认值;他们可以只是离开默认为 Noneensure_value() 会照顾到正确的时候,当需要。