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]

基本原理

虽然插值通常被认为是字符串操作,但在某些情况下,对 bytesbytearrays 进行插值是有意义的,而弥补此缺失功能所需的工作会降低代码的整体可读性。

动机

随着 Python 3 以及 strbytes 之间的分离,编程的一个小但重要的领域变得稍微困难了一些,也更加痛苦——线格式协议 [3]

这个编程领域的特点是混合了二进制数据和 ASCII 兼容的文本片段(即 ASCII 编码的文本)。为 bytesbytearray 带回受限的 %-插值将有助于编写新的线格式代码,以及移植 Python 2 线格式代码。

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

bytesbytearray 格式化的建议语义

%-插值

所有数字格式代码(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 不会接受数字或 str。拒绝 str 是因为字符串到字节的转换需要编码,而我们拒绝猜测;拒绝数字是因为

  • 什么是数字是不确定的(浮点数?十进制数?分数?某些用户类型?)
  • 允许数字会导致数字和数字的文本表示之间的歧义(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 的唯一目的是帮助从 Python 2 迁移,以及/或者拥有一个与 Python 2 共享的代码库。这很重要,因为在公开和私有环境中都存在一些模块,这些模块当前使用 Python 2 的 str 类型作为 bytes 容器,因此使用 %s 作为字节插值器。

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

建议的变体

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

  • 已拒绝,因为这会导致间歇性故障。最好让操作始终失败,以便能够正确修复问题所在。

有人建议当值为 str 时,让 %b 返回 ascii 编码的 repr(b’%b’ % ‘abc’ –> b“‘abc’”)。

  • 已拒绝,因为这会导致难以调试的故障,且故障点远离问题所在。最好让操作始终失败,以便能够轻松修复问题所在。

最初,本 PEP 还建议添加格式样式格式化,但后来决定格式及其相关机制都严格基于文本(即 str),因此将其删除。

提出了各种新的特殊方法,例如 __ascii____format_bytes__ 等;目前不需要这些方法,但如果实际使用表明此解决方案存在缺陷,则以后可以再次考虑。

另一个竞争 PEP,PEP 460 添加二进制插值和格式化,也存在。

异议

针对本 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

上次修改时间:2023-09-09 17:39:29 GMT