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

Python 增强提案

PEP 784 – 将 Zstandard 添加到标准库

作者:
Emma Harper Smith <emma at python.org>
发起人:
Gregory P. Smith <greg at krypto.org>
讨论至:
Discourse 帖子
状态:
最终版
类型:
标准跟踪
创建日期:
2025年4月6日
Python 版本:
3.14
发布历史:
2025年4月7日
决议:
2025年4月25日

目录

重要

本 PEP 是一份历史文档。最新的规范文档现在可以在 compression.zstd 找到。

×

有关如何提出更改,请参阅 PEP 1

摘要

Zstandard 是一种被广泛采用、成熟且高效的压缩标准。本 PEP 建议在 Python 标准库中添加一个新模块,其中包含 Meta 的 zstd 库(默认实现)的 Python 封装。此外,为了避免与 PyPI 上的包发生名称冲突,并为 Python 用户提供统一的接口,标准库中的压缩模块将移至 compression.* 包下。

动机

CPython 包含多种不同压缩格式的模块,例如 zlib (DEFLATE)gzipbzip2lzma,每种都广泛使用。包含流行的压缩算法符合 Python “batteries included” 的哲学,即包含广泛有用的标准和实用程序。lzma 是最新添加到 Python 3.3 的此类模块。

自那时以来,Zstandard 已成为现代**事实上的**首选压缩库,既可实现高性能压缩和解压缩,又能在合理的 CPU 和内存成本下获得高压缩比。Zstandard 实现了比 bzip2 或 zlib (DEFLATE) 更高的压缩比,同时解压缩速度明显快于 LZMA。

Zstandard 已在计算的许多不同领域中广泛采用。众多的硬件实现表明了对 Zstandard 的长期承诺,并期望 Zstandard 在未来几年仍将是压缩的**事实上的**首选。Zstandard 在 **RFC 8478** 中通过 IETF 标准化进一步证明了这一点。Zstandard 压缩也应用于 ZFSBtrfs 文件系统。

Zstandard 高效的压缩已取代其他现代压缩格式,例如 brotlilzoucl,这归因于其高效的压缩。虽然 LZ4 仍在非常高吞吐量的场景中使用,但 Zstandard 也可以在其中一些上下文中使用。虽然将 LZ4 纳入范围之外,但它将是本 PEP 引入的 compression 命名空间未来一个引人注目的补充。

PyPI 上有几个 Zstandard 的 Python 绑定,每个都有不同的 API 和绑定 zstd 库的方式。在标准库中引入官方模块的一个目标是减少 Python 用户在寻找 Zstandard 简单压缩/解压缩 API 时的困惑。现有包可以继续提供扩展 API 或集成较新 Zstandard 版本的功能。

将 Zstandard 支持添加到标准库的另一个原因是解决一个长期存在的开放问题(python/cpython#81276),该问题要求在 tarfile 模块中支持 Zstandard。这个问题在 CPython 跟踪器上的开放问题中获得了第五多的“点赞”,并引发了大量的讨论和兴趣。此外,ZIP 格式标准化了 Zstandard 压缩格式 ID,与 zipfile 模块的集成将允许使用 Zstandard 压缩打开 ZIP 归档。本 PEP 的参考实现包含与 zipfiletarfileshutil 模块的集成。

Zstandard 压缩还可以用于减小 Python wheel 包的大小,并显著加快安装速度。Anaconda 发现,当采用 Zstandard 用于 conda 包格式时,速度有显著提升。

Conda 的下载大小减少了约 30-40%,并且解压速度显著加快。 […] 我们看到了大约 2.5 倍的整体加速,这几乎全部归功于新文件格式中使用的 zstd 压缩的解压速度显著加快。

Anaconda 关于 Zstandard 采用的博客

根据 lzbench(一个对许多不同压缩库和格式进行全面基准测试的工具),与 wheel 现有基于 zlib 的压缩相比,Zstandard 具有显著更高的压缩比。虽然本 PEP**不**规定对 wheel 格式或其他打包标准进行任何更改,但标准库中包含 Zstandard 绑定将使未来的 PEP 能够改善 Python wheel 包的用户体验。

基本原理

引入 compression

PyPI 上的项目已经占用了 zstdzstandard 这两个导入名称。为了避免破坏现有绑定用户,本 PEP 建议为压缩库引入一个新的命名空间,即 compression。这个名称在 PyPI 上已为标准库保留。新的 Zstandard 模块将被命名为 compression.zstd。其他压缩模块将在新的 compression 包中重新导出。

为压缩模块提供一个公共命名空间有几个优点。首先,它减少了用户对在哪里找到压缩模块的困惑。其次,顶层 compression 模块可以提供有关可用压缩格式的信息,类似于 hashlibalgorithms_available。如果 PEP 775 被接受,也可以提供 compression.algorithms_guaranteed,列出 zlib。最后,compression 命名空间可以防止未来将其他压缩格式合并到标准库中的问题。新的压缩格式可能会在集成到 CPython 之前发布到 PyPI。因此,任何新的压缩格式导入名称在模块被考虑包含在 CPython 中时可能已经占用。将压缩模块放在包前缀下可以防止未来潜在的名称冲突问题。

希望在不同 Python 版本之间保持兼容的代码可以使用以下模式来确保兼容性

try:
    from compression.lzma import LZMAFile
except ImportError:
    from lzma import LZMAFile

这将使用较新的导入名称(如果可用),否则将回退到旧名称。

基于 pyzstd 的实现

本 PEP 的实现基于 pyzstd 项目。选择该项目的原因是其代码最初由 Ma Lin 编写,旨在上游到 CPython,他也是当今标准库中使用的输出缓冲区实现的作者。该项目此后由 Rogdham 接管,并发布到 PyPI。pyzstd 中的 API 类似于标准库中其他压缩模块(如 bz2lzma)的 API。

最低支持的 Zstandard 版本

最低支持的 Zstandard 版本选择为 v1.4.5,发布于 2020 年 5 月。选择此版本作为最低版本是基于对许多 Linux 发行版软件包仓库中可用 Zstandard 版本(包括 LTS 版本)的审查。此版本选择相当保守,以最大程度地与现有 LTS Linux 发行版兼容,但考虑到较新的 Python 版本通常作为较新发行版的一部分进行打包,因此可能会选择较新的 Zstandard 版本。

规范

compression 命名空间

将引入一个新的压缩模块命名空间,名为 compression。该包的顶层模块最初将为空,但未来可能会在顶层添加用于与压缩例程交互的标准 API。

compression.zstd 模块

将引入一个新模块 compression.zstd,其中包含与标准库中其他压缩模块(即)匹配的 Zstandard 压缩 API

  • compress() / decompress() - 用于一次性压缩或解压缩的 API
  • ZstdFile / open() - 用于与流和文件类对象交互的 API
  • ZstdCompressor / ZstdDecompressor - 用于增量压缩或解压缩的 API

它还将包含一些 Zstandard 特定的功能

  • ZstdDict / train_dict() / finalize_dict() - 用于与 Zstandard 字典交互的 API,这对于压缩许多相似的小数据块非常有用

libzstd 可选依赖项

libzstd 库将成为 CPython 的可选依赖项。如果该库不可用,compression.zstd 模块将不可用。这在 Unix 平台上作为正常构建环境检测的一部分自动处理。

在 Windows 上,libzstd 将添加到 用于构建 CPython 依赖的库的源依赖项中。

其他压缩模块

新的导入名称 compression.lzmacompression.bz2compression.gzipcompression.zlib 将在 Python 3.14 中引入,分别重新导出现有 lzmabz2gzipzlib 模块的内容。compression 子模块将成为未来规范的导入名称。当最低支持的 Python 版本要求允许时,Python 文档中将推广使用新的压缩名称而不是原始的顶层模块名称。

鉴于 _compression 模块被标记为私有,它将立即重命名为 compression._common._streams。选择新名称是由于该模块的当前内容是标准库压缩模块中与 I/O 相关的流 API 帮助程序(例如 LZMAFile)。

向后兼容性

本 PEP 不引入向后不兼容的更改。目前没有计划弃用或移除现有压缩模块。现有模块的任何弃用或移除都留待未来决定,但不会早于本 PEP 接受之日起 5 年。

安全隐患

与任何新的 C 代码一样,特别是处理可能不受信任的用户输入的代码,存在内存安全问题的风险。作者计划贡献与 libfuzzer 的集成,以实现对 _zstd 代码的模糊测试,并确保其健壮性。此外,还有许多测试用于验证压缩和解压缩例程。这些测试在使用 AddressSanitizer 编译时无错误通过。

承担一个新的依赖项也总是存在安全风险,但 zstd 库已成熟,每次提交都经过模糊测试,并且参与 Meta 的漏洞奖励计划

如何教授此内容

新模块的文档在参考实现分支中。现有模块的文档也将更新以引用新名称。

参考实现

参考实现包含 _zstd C 代码、compression.zstd 代码、对 tarfileshutilzipfile 的修改,以及每个新 API 和集成测试。它还包含其他压缩模块的重新导出。

被拒绝的想法

将模块命名为 zstdlib,并且不创建新的 compression 命名空间

不创建新的 compression 命名空间,而是寻找一个不同的名称,例如 zstdlib 作为导入名称,这是其中一个选项。也提出了其他几个名称,例如 zstlibzstdzstdcomp。在讨论中,这些名称要么太容易打错,要么不直观。此外,现有导入名称的问题可能会在未来添加到标准库的压缩格式中持续存在。LZ4 是一种常见的告诉压缩格式,在 PyPI 上有一个包 lz4,其导入名称为 lz4。与其为每种压缩格式解决这个问题,不如通过使用已经占用的 compression 命名空间一劳永逸地解决它。

在 Python 3.14 中引入一个实验性的 _zstd

由于本 PEP 在 Python 3.14 新功能截止日期临近时发布,一个建议是将包命名为私有模块 _zstd,以便打包工具可以更快地使用它,但未决定最终名称。这将为 3.15 开发期间讨论最终模块名称留出更多时间。然而,引入私有模块并不受欢迎。标准库中私有模块的外部使用预期和约定尚不明确。

引入一个标准库命名空间而不是 compression

除了 compression 命名空间之外,另一种选择是为整个标准库引入一个 std 命名空间。然而,这被认为是 3.14 版本的一个过于重大的变化,没有达成一致的语义、迁移路径或包名称。此外,未来引入 std 命名空间的 PEP 总是可以定义将 compression 子模块扁平化到 std 命名空间中。

zipfiletarfile 包含在 compression

压缩通常与归档工具一起使用,因此将 zipfiletarfile 都放在 compression 命名空间下很有吸引力。然而,压缩不仅仅用于归档工具。例如,网络请求可以进行 gzip 压缩。此外,像 tar 这样的格式本身不包含压缩,而是依赖外部压缩。因此,本 PEP 不建议将 zipfiletarfile 移到 compression 下。

不将 gzip 包含在 compression

**GZip 格式 RFC** 定义了一种格式,可以包含多个块和关于其内容的元数据。通过这种方式,GZip 与 ZIP 和 tar 等归档格式非常相似。尽管如此,在使用中,GZip 通常被视为一种压缩格式而非归档格式。从不同语言如何对 GZip 进行分类来看,普遍趋势是将其分类为压缩格式而非归档格式。

语言 压缩或归档 文档链接
Golang 压缩 https://pkg.go.dev/compress/gzip
Ruby 压缩 https://docs.ruby-lang.cn/en/master/Zlib/GzipFile.html
Rust 压缩 https://github.com/rust-lang/flate2-rs
Haskell 压缩 https://hackage.haskell.org/package/zlib
C# 压缩 https://learn.microsoft.com/en-us/dotnet/api/system.io.compression.gzipstream
Java 归档 https://docs.oracle.com/javase/8/docs/api/java/util/zip/package-summary.html
NodeJS 压缩 https://node.org.cn/api/zlib.html
Web API 压缩 https://mdn.org.cn/en-US/docs/Web/API/Compression_Streams_API
PHP 压缩 https://php.net/manual/en/function.gzcompress.php
Perl 压缩 https://perldoc.perl.net.cn/IO::Compress::Gzip

此外,Python 中的 gzip 模块主要关注单块内容,并且其 API 与其他压缩模块相似,使其非常适合 compression 命名空间。


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

最后修改:2025-05-24 04:38:02 GMT