Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 364 – 过渡到 Py3K 标准库

作者:
Barry Warsaw <barry at python.org>
状态:
已撤回
类型:
标准跟踪
创建日期:
2007年3月1日
Python 版本:
2.6
发布历史:


目录

摘要

PEP 3108 描述了 Python 3.0 版本中 Python 标准库的重组。本 PEP 描述了一种从 Python 2.x 标准库过渡到 Python 3.0 标准库的机制。这种过渡将允许并鼓励 Python 程序员从 Python 2.6 开始使用新的 Python 3.0 库名称,同时保留旧名称以实现向后兼容性。通过这种方式,Python 程序员将能够编写向前兼容的代码,而不会牺牲与现有 Python 程序的互操作性。

基本原理

PEP 3108 提出了 Python 标准库 (stdlib) 重组的理由。鼓励读者查阅该 PEP,了解有关库为何以及如何重组的详细信息。如果 PEP 3108 部分或全部被接受,那么允许 Python 程序员在 Python 2.x 中开始过渡到新的 stdlib 模块名称是有利的,以便他们可以从 Python 2.6 开始编写向前兼容的代码。

请注意,PEP 3108 建议删除一些“愚蠢的旧东西”,即不再有用或必要的模块。您正在阅读的 PEP 不涉及这一点,因为对于要删除的模块,除了停止使用这些模块之外,没有向前兼容性问题。

本 PEP 仅关注维护从旧 stdlib 名称到新 stdlib 名称映射的机制。请查阅 PEP 3108 以获取所有具体的模块重命名提案。具体请参阅标题为 Modules to Rename 的部分,了解旧名称到新名称映射的指南。本 PEP 中的少数示例仅用于说明目的,不应作为具体的重命名建议。

支持的重命名

本 PEP 明确支持至少 4 种用例

  • 简单的顶级包名称重命名,例如 StringIOstringio
  • 子包重命名,其中包名称可能重命名也可能不重命名,例如 email.MIMETextemail.mime.text
  • 扩展模块重命名,例如 cStringIOcstringio
  • 任何上述内容的第三方重命名。

本 PEP 支持的两种用例包括重命名简单的顶级模块,例如 StringIO,以及包内的模块,例如 email.MIMEText

在前一种情况下,PEP 3108 目前建议将 StringIO 重命名为 stringio,遵循 PEP 8 的建议。

在后一种情况下,Python 2.5 中分发的 email 4.0 包已经将 email.MIMEText 重命名为 email.mime.text,尽管它是在 email 包内部以一次性的、独特的黑客方式完成的。本 PEP 中描述的机制足够通用,可以处理所有模块重命名,从而不再需要 Python 2.5 的这种黑客方法(除了与早期 Python 版本的向后兼容性)。

另一个用例是支持 C 扩展模块的重命名。只要 C 模块的新名称可以导入,它就可以重新映射到新名称。例如,cStringIO 重命名为 cstringio

通过任何 Python 模块可访问的多个公共接口,也支持第三方包重命名。

不递归执行重新映射。

.mv 文件

重新映射文件称为 .mv 文件;选择该后缀是为了让人联想到 Unix 的 mv(1) 命令。.mv 文件是简单的面向行的文本文件。所有空行和以 # 开头的行都被忽略。所有其他行必须包含两个由空格分隔的字段。第一个字段是旧模块名称,第二个字段是新模块名称。两个模块名称都必须使用其完整的点路径名称指定。以下是 Python 2.6 中的一个 .mv 文件示例

# Map the various string i/o libraries to their new names
StringIO    stringio
cStringIO   cstringio

.mv 文件可以出现在文件系统中的任何位置,并且提供了一个程序化接口来解析它们并注册其中的重新映射。默认情况下,当 Python 启动时,会读取 oldlib 包中的所有 .mv 文件,并自动注册它们的重新映射。这是所有模块重新映射应该为顶级 Python 2.x 标准库模块指定的地方。

实现规范

本节提供了 Python 2.x 中模块重命名如何实现的完整规范。核心机制依赖于 PEP 302 中描述的各种导入钩子。具体来说,sys.path_importer_cachesys.pathsys.meta_path 都被用来提供必要的功能。

当 Python 的导入机制初始化时,会导入 oldlib 包。oldlib 中有一个名为 OldStdlibLoader 的类。这个类实现了 PEP 302 接口并自动实例化,不带任何参数。构造函数从 oldlib 包目录中读取所有 .mv 文件,自动注册这些 .mv 文件中找到的所有重新映射。这就是 Python 2.x 标准库重新映射的方式。

OldStdlibLoader 类不应由其他 Python 模块实例化。相反,您可以通过 sys.stdlib_remapper 实例访问全局 OldStdlibLoader 实例。如果您希望对重新映射机制进行程序化访问,请使用此实例。

一个重要的实现细节:根据 PEP 302 API 的需要,一个魔术字符串被添加到 sys.path 和模块 __path__ 属性中,以便挂接我们的重新映射加载器。这个魔术字符串目前是 <oldlib>,并且 Python 的 site.py 文件需要进行一些更改,以便将所有以 < 开头的 sys.path 条目视为特殊。具体来说,不会尝试将它们转换为绝对文件名(因为它们根本不是文件名)。

为了使重新映射导入钩子工作,模块或包必须物理地位于其新名称下。这是因为导入钩子只捕获尚未导入且无法通过 Python 内置导入规则导入的模块。因此,如果一个模块已被移动,例如从 Lib/StringIO.py 到 Lib/stringio.py,并且前者的 .pyc 文件已被删除,那么如果没有重新映射器,这将失败

import StringIO

相反,有了重新映射器,这个失败的导入将被捕获,旧名称将在已注册的重新映射中查找,在这种情况下,将找到新名称 stringio。重新映射器然后尝试导入新名称,如果成功,它将结果模块绑定到 sys.modules 中,包括旧名称和新名称。因此,上述导入将导致 sys.modules 中出现“StringIO”和“stringio”的条目,并且两者都将指向完全相同的模块对象。

请注意,除了删除所有 .mv 文件或在某些自定义启动代码中以程序方式删除它们之外,没有提议禁用重新映射机制的方法。在 Python 3.0 中,重新映射将被取消,只留下“新”名称。

程序化接口

sys.stdlib_remapper 对象中添加了几个方法,第三方包可以使用这些方法来注册自己的重新映射。但请注意,在所有情况下,从旧名称到新名称只有一个映射。如果两个 .mv 文件包含旧名称的不同映射,或者如果使用已重新映射的旧名称进行程序调用,则先前的映射将丢失。这不会影响任何已导入的模块。

sys.stdlib_remapper 对象上提供以下方法

  • read_mv_file(filename) – 读取给定文件并注册文件中找到的所有重新映射。
  • read_directory_mv_files(dirname, suffix='.mv') – 列出给定目录,读取该目录中所有具有匹配后缀(默认为 .mv)的文件。对于每个解析的文件,注册在该文件中找到的所有重新映射。
  • set_mapping(oldname, newname) – 注册从旧模块名称到新模块名称的新映射。两者都必须是模块的完整点路径名称。newname 可以是 None,在这种情况下,将删除旧名称的任何现有映射(如果没有现有映射,这不是错误)。
  • get_mapping(oldname, default=None) – 返回给定旧名称的任何已注册的新名称。如果没有已注册的重新映射,则返回 default。

未解决的问题

  • 是否应该有命令行开关和/或环境变量来禁用所有重新映射?
  • 重新映射是否应该递归发生?
  • 当包的 __init__.py 加载时,我们是否应该自动解析包目录以查找 .mv 文件?这将允许包轻松包含自己的 .mv 文件以进行重新映射。比较一下,如果我们将 email 包的 .mv 文件放在 email 包中而不是 oldlib 包中,email 包目前必须怎么做。
    # Expose old names
    import os, sys
    sys.stdlib_remapper.read_directory_mv_files(os.path.dirname(__file__))
    

    我认为我们应该自动读取包的目录,查找其中可能包含的任何 .mv 文件。

参考实现

作为对当前(截至本文撰写时)Python 2.6 svn 主干状态的补丁形式的参考实现,可在 SourceForge 补丁 #1675334 [1] 中获取。请注意,此补丁包括将 cStringIO 重命名为 cstringio,但这主要是为了说明和单元测试目的。如果补丁被接受,我们可能希望将此更改拆分到其他 PEP 3108 更改中。

参考资料


来源: https://github.com/python/peps/blob/main/peps/pep-0364.rst

最后修改: 2025-02-01 08:59:27 GMT