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

Python 增强提案

PEP 461 – 为 bytes 和 bytearray 添加 % 格式化

作者:
Ethan Furman <ethan at stoneleaf.us>
状态:
最终版
类型:
标准跟踪
创建日期:
2014年1月13日
Python 版本:
3.5
发布历史:
2014年1月14日,2014年1月15日,2014年1月17日,2014年2月22日,2014年3月25日,2014年3月27日
决议:
Python-Dev 消息

目录

摘要

本 PEP 提议为 bytesbytearray 添加类似于 Python 2 的 str 类型的 % 格式化操作 [1] [2]

基本原理

虽然插值通常被认为是字符串操作,但在 bytesbytearray 上进行插值是有意义的,而且弥补这种缺失功能所需的工作会损害代码的整体可读性。

动机

随着 Python 3 中 strbytes 的分离,一个虽小但重要的编程领域变得略微困难,也更加痛苦——线缆格式协议 [3]

这个编程领域的特点是二进制数据和 ASCII 兼容文本片段(又称 ASCII 编码文本)的混合。恢复对 bytesbytearray 的受限 %-插值将有助于编写新的线缆格式代码,并有助于移植 Python 2 的线缆格式代码。

常见的用例包括 dbfpdf 文件格式、email 格式以及 FTPHTTP 通信等。

bytes 和 bytearray 格式化的提议语义

%-插值

所有数字格式代码(diouxXeEfFgG 以及后续添加到 Python 3 的任何代码)都将得到支持,并且与 str 的工作方式相同,包括填充、对齐和其他相关修饰符(目前是 #0-、空格和 +(以及任何添加到 Python 3 的修饰符))。唯一允许的非数字代码是 cbas(它是 b 的同义词)。

对于数字代码,strbytes(或 bytearray)插值之间的唯一区别是,这些代码的结果将是 ASCII 编码文本,而不是 unicode。换句话说,对于任何数字格式代码 %x

b"%x" % val

等价于

("%x" % val).encode("ascii")

示例

>>> b'%4x' % 10
b'   a'

>>> b'%#4x' % 10
' 0xa'

>>> b'%04X' % 10
'000A'

%c 将插入一个字节,要么来自 range(256) 中的 int,要么来自长度为 1 的 bytes 参数,而不是来自 str

示例

>>> b'%c' % 48
b'0'

>>> b'%c' % b'a'
b'a'

%b 将插入一系列字节。这些字节通过以下两种方式之一收集:

  • 输入类型是否支持 Py_buffer [4]?使用它来收集必要的字节。
  • 输入类型是其他类型?使用它的 __bytes__ 方法 [5];如果没有,则抛出 TypeError

特别是,%b 不会接受数字或 strstr 被拒绝,因为字符串到字节的转换需要编码,我们拒绝猜测;数字被拒绝是因为

  • 是什么构成数字是模糊的(浮点数?Decimal?Fraction?某些用户类型?)
  • 允许数字会导致数字和数字的文本表示(3.14 与 '3.14')之间产生歧义
  • 鉴于线缆格式的性质,显式肯定优于隐式

%s 作为 %b 的同义词被包含进来,唯一目的是使 2/3 代码库更易于维护。仅限 Python 3 的代码应使用 %b

示例

>>> b'%b' % b'abc'
b'abc'

>>> b'%b' % 'some string'.encode('utf8')
b'some string'

>>> b'%b' % 3.14
Traceback (most recent call last):
...
TypeError: b'%b' does not accept 'float'

>>> b'%b' % 'hello world!'
Traceback (most recent call last):
...
TypeError: b'%b' does not accept 'str'

%a 将在插值值上给出 repr(some_obj).encode('ascii', 'backslashreplace') 的等效值。用例包括开发新协议并将标记写入流;调试进入现有协议的数据以查看问题是协议本身还是错误数据;序列化格式的回退;或者任何不适合定义 __bytes__ 但需要可读/信息性表示的情况 [6]

%r 作为 %a 的同义词被包含进来,唯一目的是使 2/3 代码库更易于维护。仅限 Python 3 的代码使用 %a [7]

示例

>>> b'%a' % 3.14
b'3.14'

>>> b'%a' % b'abc'
b"b'abc'"

>>> b'%a' % 'def'
b"'def'"

与 Python 2 的兼容性

如上所述,%s%r 的 inclusion 仅仅是为了帮助从 Python 2 迁移,和/或拥有一个与 Python 2 兼容的单一代码库。这一点很重要,因为目前在野外和内部都有一些模块使用 Python 2 的 str 类型作为 bytes 容器,因此使用 %s 作为字节插值器。

然而,在新的、仅限 Python 3 的代码中应使用 %b%a,因此 %s%r 将立即被弃用,但不会从 3.x 系列中移除 [7]

提议的变体

有人提议对 %bstr 参数自动使用 .encode('ascii','strict')

  • 被拒绝,因为这会导致间歇性故障。最好是操作总是失败,这样可以正确修复问题点。

有人提议让 %b 在值为 str 时返回 ascii 编码的 repr (b'%b' % 'abc' --> b"'abc'")。

  • 被拒绝,因为这会导致远离问题点的难以调试的故障。最好是操作总是失败,这样可以轻松修复问题点。

最初这个 PEP 也提议添加格式风格的格式化,但后来决定 format 及其相关机制都严格基于文本(又称 str),因此被放弃了。

有人提议了各种新的特殊方法,例如 __ascii____format_bytes__ 等;目前不需要此类方法,但如果实际使用表明此解决方案存在缺陷,可以稍后再次讨论。

一个竞争的 PEP,PEP 460 Add binary interpolation and formatting 也存在。

反对意见

对这个 PEP 提出的反对意见主要围绕两个主题:

  • bytesbytearray 类型用于纯二进制数据,不假定任何编码
  • 提供假定 ASCII 编码的 %-插值将是一个诱人的麻烦,并让我们回到 Python 2 的 str/unicode 文本模型的问题

正如讨论中所见,bytesbytearray 也用于混合二进制数据和 ASCII 兼容片段:dbfpdf 等文件格式,ftpemail 等网络协议。

bytesbytearray 已经有几个方法假定 ASCII 兼容编码。例如 upper()isalpha()expandtabs() 等。%-插值及其非常受限的迷你语言,不会比现有方法更麻烦。

有些人反对允许所有数字格式代码,声称仅十进制就足够了。然而,至少有两种格式(dbf 和 pdf)使用非十进制数字。

脚注


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

最后修改:2025-02-01 08:55:40 GMT