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

Python 增强提案

PEP 358 – “bytes” 对象

作者:
Neil Schemenauer <nas at arctrix.com>,Guido van Rossum <guido at python.org>
状态:
最终
类型:
标准跟踪
创建:
2006年2月15日
Python 版本:
2.6, 3.0
历史记录:


目录

更新

此 PEP 部分已被 PEP 3137 取代。

摘要

此 PEP 概述了引入原始字节序列类型。添加 bytes 类型是向基于 Unicode 的 str 对象过渡的一步,该对象将在 Python 3.0 中引入。

PEP 描述了 bytes 类型在 Python 2.6 中的工作方式,以及它在 Python 3.0 中的工作方式。(偶尔会有差异,因为在 Python 2.6 中,我们有两种字符串类型,str 和 unicode,而在 Python 3.0 中,我们只有一种字符串类型,其名称为 str,但其语义类似于 2.6 的 unicode 类型。)

动机

Python 当前的字符串对象是重载的。它们用于保存字符序列和字节序列。这种目的的重载会导致混淆和错误。在未来的 Python 版本中,字符串对象将用于保存字符数据。bytes 对象将充当字节容器的角色。最终,unicode 类型将重命名为 str,旧的 str 类型将被删除。

规范

bytes 对象存储一个可变的整数序列,这些整数的范围是 0 到 255。与字符串对象不同,索引 bytes 对象会返回一个整数。将不是整数的对象分配或比较到元素会导致 TypeError 异常。将元素分配到 0 到 255 范围之外的值会导致 ValueError 异常。.__len__() 方法返回序列中存储的整数数量(即字节数)。

bytes 对象的构造函数具有以下签名

bytes([initializer[, encoding]])

如果未提供任何参数,则创建一个包含零个元素的 bytes 对象并返回。初始化参数可以是字符串(在 2.6 中,str 或 unicode),整数的可迭代对象或单个整数。构造函数的伪代码(针对清晰的语义进行了优化,而不是针对速度)如下所示:

def bytes(initializer=0, encoding=None):
    if isinstance(initializer, int): # In 2.6, int -> (int, long)
        initializer = [0]*initializer
    elif isinstance(initializer, basestring):
        if isinstance(initializer, unicode): # In 3.0, "if True"
            if encoding is None:
                # In 3.0, raise TypeError("explicit encoding required")
                encoding = sys.getdefaultencoding()
            initializer = initializer.encode(encoding)
        initializer = [ord(c) for c in initializer]
    else:
        if encoding is not None:
            raise TypeError("no encoding allowed for this initializer")
        tmp = []
        for c in initializer:
            if not isinstance(c, int):
                raise TypeError("initializer must be iterable of ints")
            if not 0 <= c < 256:
                raise ValueError("initializer element out of range")
            tmp.append(c)
        initializer = tmp
    new = <new bytes object of length len(initializer)>
    for i, c in enumerate(initializer):
        new[i] = c
    return new

.__repr__() 方法返回一个字符串,该字符串可以计算以生成一个新的 bytes 对象,其中包含一个字节文字

>>> bytes([10, 20, 30])
b'\n\x14\x1e'

该对象具有一个 .decode() 方法,相当于 str 对象的 .decode() 方法。该对象有一个类方法 .fromhex(),它接收来自集合 [0-9a-fA-F ] 的字符的字符串并返回一个 bytes 对象(类似于 binascii.unhexlify)。例如

>>> bytes.fromhex('5c5350ff')
b'\\SP\xff'
>>> bytes.fromhex('5c 53 50 ff')
b'\\SP\xff'

该对象具有一个 .hex() 方法,它执行反向转换(类似于 binascii.hexlify

>> bytes([92, 83, 80, 255]).hex()
'5c5350ff'

bytes 对象有一些类似于列表方法的方法,另一些类似于 str 方法。以下是完整的方法列表及其近似签名

.__add__(bytes) -> bytes
.__contains__(int | bytes) -> bool
.__delitem__(int | slice) -> None
.__delslice__(int, int) -> None
.__eq__(bytes) -> bool
.__ge__(bytes) -> bool
.__getitem__(int | slice) -> int | bytes
.__getslice__(int, int) -> bytes
.__gt__(bytes) -> bool
.__iadd__(bytes) -> bytes
.__imul__(int) -> bytes
.__iter__() -> iterator
.__le__(bytes) -> bool
.__len__() -> int
.__lt__(bytes) -> bool
.__mul__(int) -> bytes
.__ne__(bytes) -> bool
.__reduce__(...) -> ...
.__reduce_ex__(...) -> ...
.__repr__() -> str
.__reversed__() -> bytes
.__rmul__(int) -> bytes
.__setitem__(int | slice, int | iterable[int]) -> None
.__setslice__(int, int, iterable[int]) -> Bote
.append(int) -> None
.count(int) -> int
.decode(str) -> str | unicode # in 3.0, only str
.endswith(bytes) -> bool
.extend(iterable[int]) -> None
.find(bytes) -> int
.index(bytes | int) -> int
.insert(int, int) -> None
.join(iterable[bytes]) -> bytes
.partition(bytes) -> (bytes, bytes, bytes)
.pop([int]) -> int
.remove(int) -> None
.replace(bytes, bytes) -> bytes
.rindex(bytes | int) -> int
.rpartition(bytes) -> (bytes, bytes, bytes)
.split(bytes) -> list[bytes]
.startswith(bytes) -> bool
.reverse() -> None
.rfind(bytes) -> int
.rindex(bytes | int) -> int
.rsplit(bytes) -> list[bytes]
.translate(bytes, [bytes]) -> bytes

请注意,明显缺少 .isupper().upper() 及其相关方法。(但请参见下面的“未解决的问题”。)没有 .__hash__(),因为该对象是可变的。没有使用 .sort() 方法的用例。

bytes 类型也支持缓冲区接口,支持读取和写入二进制(但不是字符)数据。

超出范围的问题

  • Python 3k 将拥有一个截然不同的 I/O 子系统。决定该 I/O 子系统如何工作以及与 bytes 对象交互不在此 PEP 的范围内。但是,预期二进制 I/O 将读取和写入字节,而文本 I/O 将读取字符串。由于 bytes 类型支持缓冲区接口,因此 Python 2.6 中现有的二进制 I/O 操作将支持 bytes 对象。
  • 有人建议向语言中添加一个名为 .__bytes__() 的特殊方法,以允许将对象转换为字节数组。此决定不在范围内。
  • 还提出了形式为 b"..." 的字节文字。这是 PEP 3112 的主题。

未解决的问题

  • .decode() 方法是冗余的,因为 bytes 对象 b 也可以通过调用 unicode(b, <encoding>)(在 2.6 中)或 str(b, <encoding>)(在 3.0 中)来解码。我们是否需要 encode/decode 方法?从某种意义上说,使用构造函数的拼写更简洁。
  • 需要更仔细地指定方法。
  • 需要指定腌制和编组支持。
  • 是否真的需要实现所有这些列表方法?
  • 可以考虑支持 .ljust().rjust().center(),并带有强制的第二个参数。
  • 可以考虑支持 .split(),并带有强制参数。
  • 甚至可以考虑支持 .islower().isupper().isspace().isalpha().isalnum().isdigit() 和相应的转换(.lower() 等),使用 ASCII 定义的字母、数字和空格。如果接受此建议,则 .ljust().rjust().center().split() 的情况会变得更加有力,并且它们也应该具有默认参数,使用 ASCII 空格或所有 ASCII 空格(对于 .split())。

常见问题

问:当 Unicode 对象的 encode 方法执行相同操作时,为什么还要有可选的 encoding 参数?

答:在当前版本的 Python 中,encode 方法返回一个 str 对象,我们无法在不破坏代码的情况下更改它。构造 bytes(s.encode(...)) 代价很高,因为它必须多次复制字节序列。此外,Python 通常提供两种将类型为 A 的对象转换为类型为 B 的对象的方法:要求 A 实例将自身转换为 B,或要求类型 B 从 A 创建一个新实例。根据 A 和 B 的具体情况,这两个 API 都有意义;有时出于解耦的原因,要求 A 不能了解 B,在这种情况下,您必须使用后一种方法;有时 B 不能了解 A,在这种情况下,您必须使用前一种方法。

问:如果初始化参数是 str,为什么 bytes 会忽略 encoding 参数?(这仅适用于 2.6。)

答:在这种情况下,encoding 没有合理的含义。str 对象字节数组,并且它们不知道包含的字符数据的编码。我们需要假设程序员提供了已经使用所需编码的 str 对象。如果您需要纯字节副本以外的其他内容,则需要先解码字符串。例如

bytes(s.decode(encoding1), encoding2)

问:为什么不将 encoding 参数的默认值设置为 Latin-1(或涵盖整个字节范围的其他编码)而不是 ASCII?

答:Python 的系统默认编码是 ASCII。使用该默认值似乎最不容易造成混淆。此外,在 Py3k 中,使用 Latin-1 作为默认值可能不是用户期望的。例如,他们可能更喜欢 Unicode 编码。任何默认值都不会始终如一地按预期工作。至少 ASCII 会在您尝试编码非 ASCII 数据时发出响亮的抱怨。


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

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