bytes 对象

这些函数在期望附带一个字节串形参但却附带了一个非字节串形参被调用时会引发 TypeError。

为了兼容以 null 结束的 C 字符串 PyBytesObject 的内部缓冲区总是会包括一个额外的末尾 null 字节。 这个额外字节既不计入 PyBytes_Size() 也不计入下文中函数的各种 length 和 size 参数。

type PyBytesObject

这种 PyObject 的子类型表示一个 Python 字节对象。

PyTypeObject PyBytes_Type
属于 稳定 ABI.

PyTypeObject 的实例代表一个 Python 字节类型,在 Python 层面它与 bytes 是相同的对象。

int PyBytes_Check(PyObject *o)

如果对象 o 是一个 bytes 对象或者 bytes 类型的子类型的实例则返回真值。此函数总是会成功执行。

int PyBytes_CheckExact(PyObject *o)

如果对象 o 是一个 bytes 对象但不是 bytes 类型的子类型的实例则返回真值。此函数总是会成功执行。

PyObject *PyBytes_FromString(const char *v)
返回值:新的引用。 属于 稳定 ABI. Thread safety: Atomic.

成功时返回一个以字符串 v 的副本为值的新字节串对象,失败时返回 NULL。形参 v 不可为 NULL;它不会被检查。

PyObject *PyBytes_FromStringAndSize(const char *v, Py_ssize_t len)
返回值:新的引用。 属于 稳定 ABI. Thread safety: Atomic.

成功时返回一个以字符串 v 的副本为值且长度为 len 的新字节串对象,失败时返回 NULL。如果 v 为 NULL,则不初始化字节串对象的内容。

自 3.15 版起已处于 Soft deprecated 状态: 使用 PyBytesWriter API 代替 PyBytes_FromStringAndSize(NULL, len)。

PyObject *PyBytes_FromFormat(const char *format, ...)
返回值:新的引用。 属于 稳定 ABI. Thread safety: Atomic.

接受一个 C printf() 风格的 format 字符串和可变数量的参数,计算结果 Python 字节串对象的大小并返回参数值经格式化后的字节串对象。可变数量的参数必须均为 C 类型并且必须恰好与 format 字符串中的格式字符相对应。允许使用下列格式字符:

格式字符

类型

注释

%%

不适用

文字%字符。

%c

int

一个字节,被表示为一个 C int。

%d

int

相当于 printf("%d")。[1]

%u

unsigned int

相当于 printf("%u")。[1]

%ld

long

相当于 printf("%ld")。[1]

%lu

unsigned long

相当于 printf("%lu")。[1]

%zd

Py_ssize_t

相当于 printf("%zd")。[1]

%zu

size_t

相当于 printf("%zu")。[1]

%i

int

相当于 printf("%i")。[1]

%x

int

相当于 printf("%x")。[1]

%s

const char*

以 null 为终止符的 C 字符数组。

%p

const void*

一个 C 指针的十六进制表示形式。基本等价于 printf("%p") 但它会确保以字面值 0x 开头,不论系统平台上 printf 的输出是什么。

无法识别的格式字符会导致将格式字符串的其余所有内容原样复制到结果对象,并丢弃所有多余的参数。

PyObject *PyBytes_FromFormatV(const char *format, va_list vargs)
返回值:新的引用。 属于 稳定 ABI. Thread safety: Atomic.

与 PyBytes_FromFormat() 完全相同,除了它需要两个参数。

PyObject *PyBytes_FromObject(PyObject *o)
返回值:新的引用。 属于 稳定 ABI. Thread safety: Safe for concurrent use on the same object.

返回实现了缓冲区协议的对象 o 的字节串表示形式。

备注

如果对象实现了缓冲区协议,则缓冲区在 bytes 对象创建时不可被修改。

Py_ssize_t PyBytes_Size(PyObject *o)
属于 稳定 ABI. Thread safety: Atomic.

返回字节串对象 o 中字节的长度。

Py_ssize_t PyBytes_GET_SIZE(PyObject *o)
Thread safety: Atomic.

类似于 PyBytes_Size(),但是不带错误检测。

char *PyBytes_AsString(PyObject *o)
属于 稳定 ABI. Thread safety: Safe to call from multiple threads with external synchronization only.

返回对应 o 的内容的指针。该指针指向 o 的内部缓冲区,其中包含 len(o) + 1 个字节。缓冲区的最后一个字节总是为空,不论是否存在其他空字节。该数据不可通过任何形式来修改,除非是刚使用 PyBytes_FromStringAndSize(NULL, size) 创建该对象。它不可被撤销分配。如果 o 根本不是一个字节串对象,则 PyBytes_AsString() 将返回 NULL 并引发 TypeError。

char *PyBytes_AS_STRING(PyObject *string)
Thread safety: Safe to call from multiple threads with external synchronization only.

类似于 PyBytes_AsString(),但是不带错误检测。

int PyBytes_AsStringAndSize(PyObject *obj, char **buffer, Py_ssize_t *length)
属于 稳定 ABI. Thread safety: Safe to call from multiple threads with external synchronization only.

通过输出变量 buffer 和 length 返回对象 obj 以空值作为结束的内容。成功时返回 0。

如果 length 为 NULL,字节串对象不可包含嵌入的空字节;如果包含,则该函数将返回 -1 并引发 ValueError 异常。

该缓冲区指向 obj 的内部缓冲,它的末尾包含一个额外的空字节(不算在 length 当中)。该数据不可通过任何方式来修改,除非是刚使用 PyBytes_FromStringAndSize(NULL, size) 创建该对象。它不可被撤销分配。如果 obj 根本不是一个字节串对象,则 PyBytes_AsStringAndSize() 将返回 -1 并引发 TypeError 异常。

在 3.5 版本发生变更: 以前,当字节串对象中出现嵌入的空字节时将引发 TypeError。

void PyBytes_Concat(PyObject **bytes, PyObject *newpart)
属于 稳定 ABI. Thread safety: Safe for concurrent use on the same object.

Create a new bytes object 在 *bytes 中创建一个新的 bytes 对象其中包含将 newpart 的内容追加到 bytes 的结果;调用方将拥有这个新引用。 对 bytes 旧值的引用将被 "偷取"。 如果无法创建新对象,对指向 bytes 的旧引用仍然会被 "偷取",*bytes 的值将被设为 NULL,并将设置适当的异常。

备注

如果 newpart 实现了缓冲区协议,则缓冲区在新 bytes 对象创建期间不可被修改。

void PyBytes_ConcatAndDel(PyObject **bytes, PyObject *newpart)
属于 稳定 ABI. Thread safety: Safe for concurrent use on the same object.

在 *bytes 中创建一个新的字节串对象,其中包含添加到 bytes 的 newpart 的内容。此版本将释放对 newpart 的 strong reference (即递减其引用计数)。

备注

如果 newpart 实现了缓冲区协议,则缓冲区在新 bytes 对象创建期间不可被修改。

PyObject *PyBytes_Join(PyObject *sep, PyObject *iterable)
Thread safety: Safe for concurrent use on the same object.

类似于 Python 中的 sep.join(iterable)。

sep 必须为 Python bytes 对象。 (请注意 PyUnicode_Join() 接受 NULL 分隔符并会将其视为空格,而 PyBytes_Join() 则不接受 NULL 分隔符。)

iterable 必须是一个产生实现了 缓冲区协议 的对象的可迭代对象。

成功时,返回一个新的 bytes 对象。失败时,设置一个异常并返回 NULL。

在 3.14 版本加入.

备注

如果 iterable 对象实现了缓冲区协议,则缓冲区在新 bytes 对象创建期间不可被修改。

int _PyBytes_Resize(PyObject **bytes, Py_ssize_t newsize)
Thread safety: Safe to call without external synchronization on distinct objects.

改变字节串对象的大小。newsize 将为字节串对象的新长度。你可以将它当作是创建一个新的字节串对象并销毁旧的对象,但是更为高效。传入一个现有字节串对象的地址作为 lvalue(它可以被写入),以及想要的新大小。当成功时,*bytes 将存放改变大小后的字节串对象并返回 0;*bytes 中的地址可能与其输入值不同。如果重新分配失败,则位于 *bytes 的原始字节串对象将被释放,*bytes 将被设为 NULL,同时设置 MemoryError,然后返回 -1。

自 3.15 版起已处于 Soft deprecated 状态: 使用 PyBytesWriter API 代替。

PyObject *PyBytes_Repr(PyObject *bytes, int smartquotes)
属于 稳定 ABI. Thread safety: Atomic.

获取 bytes 的字符串表示形式。此函数目前被用于实现 Python 中的 bytes.__repr__()。

此函数不会进行类型检测;向 bytes 传入非字节对象或 NULL 是未定义的行为。

如果 smartquotes 为真值,表示形式将在 bytes 中存在单引号时使用带双引号的字符串而不是带单引号的字符串。例如,当 smartquotes 为真值时字节串 'Python' 将被表示为 b"'Python'",当其为假值时则为 b'\'Python\'' 这种形式。

成功时,此函数将返回一个指向包含该表示形式的 str 对象的 strong reference。失败时,此函数将返回 NULL 并设置一个异常。

PyObject *PyBytes_DecodeEscape(const char *s, Py_ssize_t len, const char *errors, Py_ssize_t unicode, const char *recode_encoding)
属于 稳定 ABI. Thread safety: Atomic.

取消带反斜杠转义的字符串 s 的转义。 s 必须不为 NULL。 len 必须为 s 的长度。

errors 必须为 "strict", "replace" 或 "ignore" 之一。如果 errors 为 NULL,则默认使用 "strict"。

成功时,此函数将返回一个指向包含未转义文本的 Python bytes 对象的 strong reference。 失败时,此函数将返回 NULL 并设置一个异常。

在 3.9 版本发生变更: unicode 和 recode_encoding 现在未被使用。

PyBytesWriter

PyBytesWriter API 可被用来创建 Python bytes 对象。

在 3.15 版本加入.

type PyBytesWriter

一个 bytes 写入器实例。

此 API 不是线程安全的。 要在多个线程同共享一个写入器,则需要使用关键节或者锁。

该实例在操作成功时必须通过 PyBytesWriter_Finish(),出错时则通过 PyBytesWriter_Discard() 来销毁。

创建, 结束, 丢弃

PyBytesWriter *PyBytesWriter_Create(Py_ssize_t size)

创建一个 PyBytesWriter 来写入 size 个字节。

如果 size 大于零,则分配 size 字节,并将写入器大小设置为 size。调用者负责使用 PyBytesWriter_GetData() 写入 size 字节。此函数不会过度分配。

发生错误时,将设置异常并返回 NULL。

size 必须为正数或零。

PyObject *PyBytesWriter_Finish(PyBytesWriter *writer)

完成由 PyBytesWriter_Create() 创建的 PyBytesWriter。

成功时,返回一个 Python bytes 对象;出错时,设置一个异常并返回 NULL。

无论如何,在调用之后,writer 实例都将处于无效状态。在 PyBytesWriter_Finish() 之后,无法对 writer 调用任何 API。

PyObject *PyBytesWriter_FinishWithSize(PyBytesWriter *writer, Py_ssize_t size)

与 PyBytesWriter_Finish() 类似,但在创建 bytes 对象之前,将写入器调整为 size 字节大小。

PyObject *PyBytesWriter_FinishWithPointer(PyBytesWriter *writer, void *buf)

与 PyBytesWriter_Finish() 类似,但在创建 bytes 对象之前,使用 buf 指针调整写入器的尺寸。

设置一个异常,若 buf 指针位于内部缓冲区边界之外,则返回 NULL。

函数伪代码:

Py_ssize_t size = (char*)buf - (char*)PyBytesWriter_GetData(writer);
return PyBytesWriter_FinishWithSize(writer, size);
void PyBytesWriter_Discard(PyBytesWriter *writer)

丢弃由 PyBytesWriter_Create() 创建的 PyBytesWriter。

如果 writer 为 NULL,则什么都不做。

调用后,写入器实例已无效。在 PyBytesWriter_Discard() 之后,无法对写入器调用任何 API。

高阶 API

int PyBytesWriter_WriteBytes(PyBytesWriter *writer, const void *bytes, Py_ssize_t size)

将 writer 的内部缓冲区扩展 size 字节;在 writer 端写入 size 字节的 bytes;并将 size 加到 writer 的大小中。

如果 size 等于 -1,则调用 strlen(bytes) 以获取字符串长度。

如果成功,返回 0。如果发生错误,设置异常并返回 -1。

int PyBytesWriter_Format(PyBytesWriter *writer, const char *format, ...)

与 PyBytes_FromFormat() 类似,但将输出直接写入写入器末尾。按需扩展写入器的内部缓冲区,然后把已写入的大小累加到写入器的大小中。

如果成功,返回 0。如果发生错误,设置异常并返回 -1。

获取器

Py_ssize_t PyBytesWriter_GetSize(PyBytesWriter *writer)

获取写入器的大小。

该函数不会使 PyBytesWriter_GetData() 返回的指针失效。

函数不能失败。

void *PyBytesWriter_GetData(PyBytesWriter *writer)

获取写入数据:从内部缓冲区起始位置开始。

该指针将持续有效,直到在 writer 上调用除 PyBytesWriter_GetData() 或 PyBytesWriter_GetSize() 之外的其他 PyBytesWriter 函数为止。

函数不能失败。

底层级 API

int PyBytesWriter_Resize(PyBytesWriter *writer, Py_ssize_t size)

将写入器调整为 size 字节大小。此函数可用于增大或缩小写入器。在多次调整大小时,该函数通常会采用过度分配的方式,以实现摊还性能。

新分配的字节是未初始化的。

如果成功,返回 0。如果发生错误,设置异常并返回 -1。

size 必须为正数或零。

int PyBytesWriter_Grow(PyBytesWriter *writer, Py_ssize_t grow)

通过向当前写入器大小添加 grow 字节来调整写入器的大小。该函数通常会进行过度分配,从而在多次调整大小时实现摊还性能。

新分配的字节是未初始化的。

如果成功,返回 0。如果发生错误,设置异常并返回 -1。

grow 可以为负数,以缩小写入器。

void *PyBytesWriter_GrowAndUpdatePointer(PyBytesWriter *writer, Py_ssize_t size, void *buf)

与 PyBytesWriter_Grow() 类似,但还需更新 buf 指针。

如果内部缓冲区在内存中发生移动,则 buf 指针也会随之移动;buf 在内部缓冲区内的相对位置保持不变。

发生错误时,将设置异常并返回 NULL。

buf 不得为 NULL。

函数伪代码:

Py_ssize_t pos = (char*)buf - (char*)PyBytesWriter_GetData(writer);
if (PyBytesWriter_Grow(writer, size) < 0) {
    return NULL;
}
return (char*)PyBytesWriter_GetData(writer) + pos;

创建字符串 b'abc' 的示例

示例:创建字节字符串 b"abc",其固定大小为 3 字节:

PyObject* create_abc(void)
{
    PyBytesWriter *writer = PyBytesWriter_Create(3);
    if (writer == NULL) {
        return NULL;
    }

    char *str = PyBytesWriter_GetData(writer);
    memcpy(str, "abc", 3);
    return PyBytesWriter_Finish(writer);
}

使用指针计算最终大小的变体:

PyObject* create_abc_ptr(void)
{
    PyBytesWriter *writer = PyBytesWriter_Create(3);
    if (writer == NULL) {
        return NULL;
    }

    char *str = PyBytesWriter_GetData(writer);
    memcpy(str, "abc", 3);
    str += 3;
    return PyBytesWriter_FinishWithPointer(writer, str);
}

Update PyBytes_FromStringAndSize() code

使用已软弃用的 PyBytes_FromStringAndSize(NULL, size) API 的代码示例:

int copy_bytes(char *dest, const char *src, Py_ssize_t num_bytes)
{
    ...
}

PyObject* create_string(const char *start, Py_ssize_t num_bytes)
{
    PyObject *result = PyBytes_FromStringAndSize(NULL, num_bytes);
    if (result == NULL) {
        return NULL;
    }
    if (copy_bytes(PyBytes_AS_STRING(result), start, num_bytes) < 0) {
        Py_CLEAR(result);
    }
    return result;
}

现在可以将其更新为:

PyObject* create_string(const char *start, Py_ssize_t num_bytes)
{
    PyBytesWriter *writer = PyBytesWriter_Create(num_bytes);
    if (writer == NULL) {
        return NULL;
    }
    if (copy_bytes(PyBytesWriter_GetData(writer), start, num_bytes) < 0) {
        PyBytesWriter_Discard(writer);
        return NULL;
    }
    return PyBytesWriter_Finish(writer);
}

Update _PyBytes_Resize() code

使用已软弃用的 _PyBytes_Resize() API 的代码示例:

PyObject* create_string(Py_ssize_t size)
{
    PyObject *bytes = PyBytes_FromStringAndSize(NULL, size);
    if (bytes == NULL) {
        return NULL;
    }
    char *str = PyBytes_AS_STRING(bytes);

    // ... write data into str ...

    if (_PyBytes_Resize(&bytes, (str - PyBytes_AS_STRING(bytes)))) {
        return NULL;
    }
    return bytes;
}

现在可以将其更新为:

PyObject* create_string(Py_ssize_t size)
{
    PyBytesWriter *writer = PyBytesWriter_Create(size);
    if (writer == NULL) {
        return NULL;
    }
    char *str = PyBytesWriter_GetData(writer);

    // ... write data into str ...

    return PyBytesWriter_FinishWithPointer(writer, str);
}