PEP 389 – argparse - 新的命令行解析模块
- 作者:
- Steven Bethard <steven.bethard at gmail.com>
- 状态:
- 最终
- 类型:
- 标准跟踪
- 创建:
- 2009年9月25日
- Python 版本:
- 2.7, 3.2
- 历史记录:
- 2009年9月27日,2009年10月24日
接受
此 PEP 于 2010 年 2 月 21 日在 python-dev 上获得 Guido 批准 [17]。
摘要
此 PEP 提出将 argparse [1] 模块包含在 Python 2.7 和 3.2 中的 Python 标准库中。
动机
argparse 模块是一个命令行解析库,它提供了比标准库中现有的命令行解析模块 getopt [2] 和 optparse [3] 更多的功能。它包括对位置参数(不仅仅是选项)、子命令、必填选项、像“/f”和“+rgb”这样的选项语法、零个或多个和一个或多个样式的参数以及其他两个模块缺少的许多其他功能的支持。
argparse 模块也已经是这些模块的流行第三方替代品。它被用于 IPython(Scipy Python shell)等项目 [4],包含在 Debian testing 和 unstable 中 [5],并且自 2007 年以来,一直有各种将其包含在标准库中的请求 [6] [7] [8]。这种受欢迎程度表明它可能是 Python 库的有价值的补充。
为什么 getopt 和 optparse 不够用?
反对添加 argparse 的一个论点是,“标准库中已经有两种不同的选项解析模块” [9]。以下是 argparse 提供但 getopt 或 optparse 中不存在的功能列表
- 虽然确实有两个选项解析库,但没有完整的命令行解析库——getopt 和 optparse 都只支持选项,并且不支持位置参数。argparse 模块同时处理两者,因此能够生成更好的帮助消息,避免像 optparse 通常需要的
usage=
字符串这样的冗余。 - argparse 模块重视实用性而非纯净性。因此,argparse 允许必填选项和自定义用于识别选项的字符,而 optparse 明确指出“‘必填选项’这个短语本身就是自相矛盾的”,并且选项语法
-pf
、-file
、+f
、+rgb
、/f
和/file
“不受 optparse 支持,将来也不会支持”。 - argparse 模块允许选项使用
nargs='?'
、nargs='*'
或nargs='+'
接受可变数量的参数。optparse 模块提供了一个未经测试的配方,用于实现此功能的一部分 [10],但承认“当您希望一个选项采用可变数量的参数时,事情就会变得复杂”。 - argparse 模块支持子命令,其中主命令行解析器根据命令行参数分派到其他命令行解析器。这在命令行界面中是一种常见模式,例如
svn co
和svn up
。
为什么不只是向 optparse 添加功能?
显然,以上所有功能都比 optparse 提供的功能有所改进。那么一个合理的问题是,为什么这些功能不是简单地作为补丁提供给 optparse,而是引入一个全新的模块。事实上,argparse 的最初开发就是为了做到这一点,但由于 optparse 的一些相当严格的设计决策,这实际上是不可能的。一些问题包括
- optparse 模块公开了其解析算法的内部细节。特别是,
parser.largs
和parser.rargs
确保可用于回调 [11]。这使得改进解析算法变得极其困难,而 argparse 中的正确处理位置参数和可变长度参数需要这样做。例如,argparse 中的nargs='+'
是使用正则表达式匹配的,因此没有parser.largs
之类的东西的概念。 - optparse 扩展 API 极其复杂。例如,只需使用一个简单的自定义字符串到对象的转换函数,您就必须子类化
Option
,修改类属性,然后将您的自定义选项类型指定给解析器,如下所示class MyOption(Option): TYPES = Option.TYPES + ("mytype",) TYPE_CHECKER = copy(Option.TYPE_CHECKER) TYPE_CHECKER["mytype"] = check_mytype parser = optparse.OptionParser(option_class=MyOption) parser.add_option("-m", type="mytype")
相比之下,argparse 只允许将转换函数直接用作
type=
参数,例如parser = argparse.ArgumentParser() parser.add_option("-m", type=check_mytype)
但是鉴于 optparse 的繁复的自定义 API,不清楚这样的功能应该如何与这些 API 交互,并且很有可能引入简单的 argparse API 会破坏现有的自定义 Option 代码。
- optparse 和 argparse 都解析命令行参数并将它们作为属性分配给
parse_args
返回的对象。但是,optparse 模块保证自定义操作的take_action
方法将始终传递一个values
对象,该对象提供一个ensure_value
方法 [12],而 argparse 模块允许将属性分配给任何对象,例如foo_object = ... parser.parse_args(namespace=foo_object) foo_object.some_attribute_parsed_from_command_line
修改 optparse 以允许传递任何对象将很困难,因为仅仅传递
foo_object
而不是Values
实例将破坏依赖于ensure_value
方法的现有自定义操作。
由于这些问题,使得 argparse 难以与 optparse API 保持兼容,因此 argparse 被开发为一个独立的模块。鉴于这些问题,将所有 argparse 功能合并到 optparse 中而没有任何向后兼容性似乎不太可能。
optparse 的弃用
因为 argparse 中提供了 optparse 的所有功能,所以 optparse 模块将被弃用。但是,由于 optparse 的广泛使用,弃用策略仅包含文档更改和默认情况下不可见的警告
- Python 2.7+ 和 3.2+ – 将在 optparse 文档中添加以下说明optparse 模块已弃用,并且不会进一步开发;开发将继续使用 argparse 模块。
- Python 2.7+ – 如果在命令行中提供了 Python 3 兼容性标志
-3
,则导入 optparse 将发出 DeprecationWarning。否则不会发出任何警告。 - Python 3.2+ – 导入 optparse 将发出 PendingDeprecationWarning,默认情况下不会显示。
请注意,没有为 optparse 提出删除日期。
getopt 文档更新
getopt 模块不会被弃用。但是,其文档将在几个地方更新为指向 argparse。在模块顶部,将添加以下说明
getopt 模块是命令行选项的解析器,其 API 设计为对 C getopt 函数的用户熟悉。不熟悉 C getopt 函数或希望编写更少代码并获得更好帮助和错误消息的用户应该考虑改用 argparse 模块。
此外,在最后一个 getopt 示例之后,将添加以下说明
请注意,可以使用 argparse 模块以更少的代码生成等效的命令行界面import argparse if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('-o', '--output') parser.add_argument('-v', dest='verbose', action='store_true') args = parser.parse_args() # ... do something with args.output ... # ... do something with args.verbose ..
延迟:字符串格式化
argparse 模块支持从 2.3 到 3.2 的 Python,因此依赖于传统的 %(foo)s
样式字符串格式化。有人建议最好使用新的 {foo}
样式字符串格式化 [13]。关于如何最好地为标准库中的模块执行此操作进行了一些讨论 [14],并且有几个人正在开发用于自动将 %-格式转换为 {}-格式的函数 [15] [16]。当其中一个添加到标准库时,argparse 将使用它们来支持两种格式化样式。
拒绝:getopt 兼容方法
以前,当此 PEP 还建议弃用 getopt 和 optparse 时,有人谈到添加像这样的方法
ArgumentParser.add_getopt_arguments(options[, long_options])
但是,出于多种原因,此方法不会被添加
- getopt 模块没有被弃用,因此需求减少。
- 此方法实际上并不会简化任何已经维护使用消息的 getopt 用户的过渡,因为上面的 API 无法为参数添加帮助消息。
- 一些 getopt 用户认为仅需要一个函数调用非常重要。上面的 API 无法满足此要求,因为还必须调用
ArgumentParser()
和parse_args()
。
超出范围:各种功能请求
在讨论此 PEP 时,对 argparse 做出了几个功能请求
- 支持从环境变量获取参数默认值
- 支持从配置文件获取参数默认值
- 除了当前支持的“foo subcommand –help”之外,还支持“foo –help subcommand”
这些都是 argparse 模块的合理功能请求,但不在此 PEP 的范围内,并且已重定向到 argparse 问题跟踪器。
讨论:sys.stderr 和 sys.exit
有些人担心 argparse 默认情况下总是写入 sys.stderr
,并在提供无效参数时始终调用 sys.exit
。对于绝大多数围绕简单命令行接口的 argparse 使用案例来说,这是期望的行为。但是,在某些情况下,可能希望阻止 argparse 退出,或者使其将消息写入 sys.stderr
以外的位置。可以通过继承 ArgumentParser
并覆盖 exit
或 _print_message
方法来支持这些用例。后者是一个未公开的实现细节,但如果证明这是一个普遍的需求,可以正式公开。
参考文献
版权
本文档已进入公有领域。
来源: https://github.com/python/peps/blob/main/peps/pep-0389.rst
上次修改时间: 2023-09-09 17:39:29 GMT