注意: 虽然 JavaScript 对本网站不是必需的,但您与内容的互动将会受到限制。请启用 JavaScript 以获得完整体验。

选项解析库比较

选项解析库比较

注意:此页面仅供历史参考。getopt-sig 已退役,Optik 已在 Python 2.3 中添加到 Python 标准库(作为 optparse)。(它于 2002 年 11 月被签入 Python 的 CVS 树,并于 2003 年 7 月首次发布。)

自从我为 Python 标准库提议 Optik 以来,已经出现了一些其他的选项解析库。我正在尝试通过使用几种不同的库实现相同的真实世界命令行界面来评估它们。目前,存在以下库的实现:

  • Greg Ward 的(那就是我)Optik
  • Russ Cox 的迭代器接口(ArgParser
  • Albert Hofkamp 的 argtools(页面不再可用)
  • David Boddie 的 CMDSyntax(页面不再可用)

用户界面

我选择实现的接口是我 ripoff CD 翻录脚本的接口。此接口的主要功能是:

  • 直接、标准接口(选项之间没有复杂的交互)
  • 相当多的选项(大约 17 个)——足够多的数量,以至于某种高层命令行解析帮助确实很有用,但又不会多到需要我永远重复实现该接口多次
  • 各种选项类型和操作(使用 Optik 的术语)(但没有任何真正神秘或不寻常的东西)
  • 不期望或允许位置参数——即,Ripoff 需要知道的一切都可以从命令行选项中获取。

为了保持具体性,这里是 Ripoff 的帮助文本(由 Optik 生成)。

Ripoff 的命令行接口的一个弱点是,一些标志选项没有负对应项:例如,有一个 --keep-tmp 选项,但没有 --no-keep-tmp。这种事情在现实世界中确实是必要的,在现实世界中,程序的默认值(在本例中为 no-keep-tmp)可能会被配置文件覆盖,然后在命令行上再次覆盖。此弱点目前反映在我所有三个测试重新实现中。

内部接口

在内部,Ripoff 的工作方式是传递一个包含命令行所有值的单个对象。例如,用户选择的详细级别在 options.verbose 中,CD-ROM 设备文件在 options.device 中。选项值的数量没有选项的数量那么多:-v/--verbose 选项和 -q/--quiet 都会更新 options.verbose,而 -p/--use-pipes 和 -f/--use-files 都会更新 options.use_pipes 标志。

我已经在我的所有测试重新实现中保留了这一点。这对 Optik 有利(因为它已经将选项值放在了一个专用对象中);对迭代器版本没有太大影响(这只是意味着需要多打一些字);并且它使 argtools 看起来很糟糕,因为我必须显式地将所有选项值从解析器对象复制到我的专用选项值对象。

现在,女士们先生们...

不要再耽误时间了,开始表演吧!首先,关于三个重新实现的一些简单统计数据:
总代码[1] 代码(无帮助)[2]
Optik 6234
迭代器11273
argtools10869
注释
  1. 如 Dinu Gherman 的 pycount 报告的那样——即,这是实际代码的行数,不计算空白、注释或文档字符串(但计算文字字符串,例如帮助和用法文本)
  2. 即,删除了所有显式帮助文本。对于 ArgParser 和 argtools,这只是一个大的文字字符串,因为这些库不进行自动帮助生成。对于 Optik,这只是意味着从每个选项中删除 help 参数;即使删除此每个选项的帮助文本,Optik 仍然会提供一个 --help 选项,该选项报告哪些选项可用

但正如马克·吐温所说:有谎言、该死的谎言和统计数据。所以让我们看看一些代码。

  • ripoff_optik.py 是使用 Optik 实现的 Ripoff 的命令行界面(当然是从 Ripoff 源代码中直接剪切出来的)
  • ripoff_iterator.py 是使用 Russ Cox 的迭代器接口进行的重新实现
  • ripoff_argtools.py 是使用 Albert Hofkamp 的 argtools 进行的重新实现
  • 由 David Boddie 提供的 CMDSyntax 的示例代码(页面不再可用)

如果您实际上想在不修改它们的情况下运行这些示例,则需要从 其 CVS 存储库 获取 Ripoff 源代码。这是因为我想要 1) 一个真实的 --version 选项(使用 ripoff.__version__)和 2) -d/--device 选项的真实帮助(它依赖于 ripoff.cdrom 扩展模块,特别是 get_default_device() 函数)。但这里的真正目的是检查代码,而不是运行它。