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

Python 增强提案

PEP 3137 – 不可变字节和可变缓冲区

作者:
Guido van Rossum <guido at python.org>
状态:
最终版
类型:
标准跟踪
创建日期:
2007年9月26日
Python 版本:
3.0
发布历史:
2007年9月26日,2007年9月30日

目录

引言

在发布带有可变字节类型的 Python 3.0a1 后,表示不可变字节的需求日益增加。Gregory P. Smith 提出了一个补丁,允许通过请求使用 PEP 3118 中的新缓冲区 API 锁定数据,从而使字节对象暂时不可变。这对我来说似乎不是正确的方法。

Jeffrey Yasskin 在 Adam Hupp 的帮助下,准备了一个补丁,使字节类型不可变(通过粗略地删除所有变异 API),并修复了测试套件中的问题。这表明除了从零碎部分构建返回值代码之外,并没有多少地方依赖于字节的可变性。

经过深思熟虑,并注意到使用数组模块作为替代可变字节类型远非理想,回想起 Talin 早前提出的建议,我提出了同时拥有可变和不可变字节类型的建议。(这之前曾被提出过,但直到看到 Jeffrey 补丁的证据,我才接受这个建议。)

此外,一种可能的实现策略变得清晰:使用旧的 PyString 实现,剥离掉本地化支持和与 Unicode 的隐式转换,用于不可变字节类型;保留新的 PyBytes 实现作为可变字节类型。

随后的讨论表明,这个想法受到欢迎,但需要更精确地指定。因此有了这个 PEP。

优点

拥有不可变字节类型的一个优点是代码对象可以使用它们。它还使得使用字节作为键高效创建哈希表成为可能;这在解析基于表示文本的字节的协议(如 HTTP 或 SMTP)时可能很有用。

使用新设计比使用原始 3.0 设计(带有可变字节)更容易移植在 Python 2.x 中操作二进制数据(或编码文本)的代码;只需将 str 替换为 bytes,并将 ‘…’ 字面量更改为 b’…’ 字面量。

命名

我建议在 Python 级别使用以下类型名称

  • bytes 是一个不可变字节数组 (PyString)
  • bytearray 是一个可变字节数组 (PyBytes)
  • memoryview 是另一个对象上的字节视图 (PyMemory)

旧的 buffer 类型与 PEP 3118 引入的新类型 memoryview 非常相似,因此它是冗余的。本 PEP 的其余部分不讨论 memoryview 的功能;这里只是提及它,以证明摆脱旧 buffer 类型是合理的。(本 PEP 的早期版本曾提议将 buffer 作为 PyBytes 的新名称;最终,考虑到 “buffer” 一词的许多其他用法,该名称被认为过于容易混淆。)

虽然最终更改 C API 名称是有意义的,但本 PEP 保持了旧的 C API 名称,这应该对所有人都很熟悉。

总结

下面是一个简单的 ASCII 艺术表格,总结了各种 Python 版本中的类型名称

+--------------+-------------+------------+--------------------------+
| C name       | 2.x    repr | 3.0a1 repr | 3.0a2               repr |
+--------------+-------------+------------+--------------------------+
| PyUnicode    | unicode u'' | str     '' | str                   '' |
| PyString     | str      '' | str8   s'' | bytes                b'' |
| PyBytes      | N/A         | bytes  b'' | bytearray bytearray(b'') |
| PyBuffer     | buffer      | buffer     | N/A                      |
| PyMemoryView | N/A         | memoryview | memoryview         <...> |
+--------------+-------------+------------+--------------------------+

字面量表示法

Python 3.0a1 中引入的 b’…’ 表示法返回一个不可变字节对象,无论使用哪种变体。要创建一个可变字节数组,请使用 bytearray(b’…’) 或 bytearray([…])。后一种形式接受一个范围在 range(256) 内的整数列表。

功能

PEP 3118 缓冲区 API

bytes 和 bytearray 都实现了 PEP 3118 缓冲区 API。bytes 类型只实现只读请求;bytearray 类型也允许可写和数据锁定请求。元素数据类型始终是 ‘B’(即无符号字节)。

构造函数

bytes 和 bytearray 都有四种形式的构造函数:

  • bytes(<bytes>), bytes(<bytearray>), bytearray(<bytes>), bytearray(<bytearray>): 简单的复制构造函数,需要注意的是 bytes(<bytes>) 可能会返回其(不可变)参数,但 bytearray(<bytearray>) 总是会创建副本。
  • bytes(<str>, <encoding>[, <errors>]), bytearray(<str>, <encoding>[, <errors>]): 编码文本字符串。请注意,str.encode() 方法返回一个 不可变 字节对象。 参数是必需的; 是可选的。(如果给定)必须是 str 实例。
  • bytes(<memory view>), bytearray(<memory view>): 从任何实现 PEP 3118 缓冲区 API 的对象构造 bytes 或 bytearray 对象。
  • bytes(<iterable of ints>), bytearray(<iterable of ints>): 从范围在 range(256) 内的整数流构造 bytes 或 bytearray 对象。
  • bytes(<int>), bytearray(<int>): 构造给定长度的零初始化 bytes 或 bytearray 对象。

比较

bytes 和 bytearray 类型可以相互比较和排序,因此例如 b’abc’ == bytearray(b’abc’) < b’abd’。

将任一类型与字符串对象进行相等比较会返回 False,无论操作数内容如何。与字符串进行排序比较会引发 TypeError。这都符合不兼容类型对象之间比较和排序的标准规则。

(注意: 在 Python 3.0a1 中,比较字节实例和字符串实例会引发 TypeError,前提是这可以更快地捕获偶尔的错误,尤其是在从 Python 2.x 移植的代码中。然而,python-3000 列表上的长时间讨论指出了许多问题,这显然是一个坏主意,无论本 PEP 的其余部分命运如何,都将在 3.0a2 中回滚。)

切片

对 bytes 对象进行切片会返回 bytes 对象。对 bytearray 对象进行切片会返回 bytearray 对象。

对 bytearray 对象的切片赋值接受任何实现 PEP 3118 缓冲区 API 的对象,或范围在 range(256) 内的整数可迭代对象。

索引

对 bytes 和 bytearray 进行索引返回小整数(与 3.0a1 中的 bytes 类型以及列表或 array.array(‘B’) 类似)。

对 bytearray 对象的项赋值接受范围在 range(256) 内的整数。(要从 bytes 序列赋值,请使用切片赋值。)

Str() 和 Repr()

str() 和 repr() 函数对这些对象返回相同的值。bytes 对象的 repr() 返回 b’…’ 样式字面量。bytearray 的 repr() 返回形式为 “bytearray(b’…’)” 的字符串。

运算符

bytes 和 bytearray 类型实现了以下运算符,除非另有说明:

  • b1 + b2: 拼接。对于混合 bytes/bytearray 操作数,返回类型是第一个参数的类型(这看起来是任意的,直到你考虑 += 的工作原理)。
  • b1 += b2: 如果 b1 是 bytearray 对象,则改变 b1。
  • b * n, n * b: 重复;n 必须是整数。
  • b *= n: 如果 b 是 bytearray 对象,则改变 b。
  • b1 in b2, b1 not in b2: 子字符串测试;b1 可以是任何实现 PEP 3118 缓冲区 API 的对象。
  • i in b, i not in b: 单字节成员测试;i 必须是整数(如果它是一个长度为 1 的字节数组,则被视为子字符串测试,结果相同)。
  • len(b): 字节数。
  • hash(b): 哈希值;仅由 bytes 类型实现。

请注意,不实现 % 运算符。它似乎不值得复杂。

方法

以下方法由 bytes 和 bytearray 实现,语义相似。它们接受任何实现 PEP 3118 缓冲区 API 的对象作为 bytes 参数,并返回与调用该方法的对象(“self”)相同的类型:

.capitalize(), .center(), .count(), .decode(), .endswith(),
.expandtabs(), .find(), .index(), .isalnum(), .isalpha(), .isdigit(),
.islower(), .isspace(), .istitle(), .isupper(), .join(), .ljust(),
.lower(), .lstrip(), .partition(), .replace(), .rfind(), .rindex(),
.rjust(), .rpartition(), .rsplit(), .rstrip(), .split(),
.splitlines(), .startswith(), .strip(), .swapcase(), .title(),
.translate(), .upper(), .zfill()

这正是 Python 2.x 中 str 类型上存在的方法集,不包括 .encode()。签名和语义也相同。但是,每当使用字符类(如字母、空白、小写)时,都使用这些类的 ASCII 定义。(Python 2.x str 类型使用当前区域设置中的定义,可通过 locale 模块设置。)之所以省略 .encode() 方法,是因为 Python 3000 中对编码和解码的定义更严格:编码总是接受 Unicode 字符串并返回字节序列,而解码总是接受字节序列并返回 Unicode 字符串。

此外,这两种类型都实现了类方法 .fromhex(),它从包含十六进制值(字节之间可以有或没有空格)的字符串构造对象。

bytearray 类型实现了 MutableSequence ABC 中的这些额外方法(参见 PEP 3119):

.extend(), .insert(), .append(), .reverse(), .pop(), .remove()。

字节和字符串类型

与 Python 3.0a1 中的 bytes 类型一样,与 Python 2.x 中 str 和 unicode 之间的关系不同,尝试混合 bytes(或 bytearray)对象和 str 对象而不指定编码将引发 TypeError 异常。(但是,比较 bytes/bytearray 和 str 对象的相等性将简单地返回 False;请参阅上面的比较部分。)

bytes 或 bytearray 对象与 str 对象之间的转换必须始终是显式的,并使用编码。有两种等效的 API:str(b, <encoding>[, <errors>]) 等效于 b.decode(<encoding>[, <errors>]),而 bytes(s, <encoding>[, <errors>]) 等效于 s.encode(<encoding>[, <errors>])

有一个例外:我们可以通过编写 str(b) 将 bytes(或 bytearray)转换为 str 而无需指定编码。这会产生与 repr(b) 相同的结果。这个例外是必要的,因为我们普遍承诺 任何 对象都可以打印,而打印只是转换为 str 的一种特殊情况。但是,不承诺打印 bytes 对象会将单个字节解释为字符(与 Python 2.x 不同)。

str 类型目前实现了 PEP 3118 缓冲区 API。虽然这可能偶尔很方便,但也可能令人困惑,因为通过缓冲区 API 访问的字节表示依赖于平台的编码:根据平台字节顺序和编译时配置选项,编码可能是 UTF-16-BE、UTF-16-LE、UTF-32-BE 或 UTF-32-LE。更糟糕的是,str 类型的不同实现可能会完全改变字节表示,例如改为 UTF-8,甚至根本不可能将数据作为连续的字节数组访问。因此,将从 str 类型中删除 PEP 3118 缓冲区 API。

basestring 类型

basestring 类型将从语言中删除。以前使用 isinstance(x, basestring) 的代码应更改为使用 isinstance(x, str)

序列化

留给读者作为练习。


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

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