Python >= 3.3 内部字符串表示
Posted
技术标签:
【中文标题】Python >= 3.3 内部字符串表示【英文标题】:Python >= 3.3 Internal String Representation 【发布时间】:2020-10-05 15:42:02 【问题描述】:我正在研究 PEP 393 之后 Python 如何表示字符串,但我不了解 PyASCIIObject 和 PyCompactUnicodeObject 之间的区别。
我的理解是字符串用以下结构表示:
typedef struct
PyObject_HEAD
Py_ssize_t length; /* Number of code points in the string */
Py_hash_t hash; /* Hash value; -1 if not set */
struct
unsigned int interned:2;
unsigned int kind:3;
unsigned int compact:1;
unsigned int ascii:1;
unsigned int ready:1;
unsigned int :24;
state;
wchar_t *wstr; /* wchar_t representation (null-terminated) */
PyASCIIObject;
typedef struct
PyASCIIObject _base;
Py_ssize_t utf8_length;
char *utf8;
Py_ssize_t wstr_length;
PyCompactUnicodeObject;
typedef struct
PyCompactUnicodeObject _base;
union
void *any;
Py_UCS1 *latin1;
Py_UCS2 *ucs2;
Py_UCS4 *ucs4;
data;
PyUnicodeObject;
如果我错了,请纠正我,但我的理解是 PyASCIIObject 仅用于具有 ASCII 字符的字符串,PyCompactUnicodeObject 使用 PyASCIIObject 结构,它用于具有至少一个非 ASCII 字符的字符串,而 PyUnicodeObject 用于遗留功能。对吗?
另外,为什么 PyASCIIObject 使用 wchar_t? char 还不足以表示 ASCII 字符串吗? 另外,如果 PyASCIIObject 已经有一个 wchar_t 指针,为什么 PyCompactUnicodeObject 也有一个 char 指针?我的理解是两个指针都指向同一个位置,但是为什么要同时包含两者呢?
【问题讨论】:
【参考方案1】:PEP 373 确实是您问题的最佳参考,尽管有时也需要the C-API docs。让我们一一解答您的问题:
你有正确的类型。但是有一个不明显的问题:当您使用任何一种“紧凑”类型(PyASCIIObject
或PyCompactUnicodeObject
)时,结构本身只是一个标题。字符串的实际数据在结构之后立即存储在内存中。数据使用的编码由kind
字段描述,并将取决于字符串中的最大字符值。
前两个结构中的wstr
和utf8
指针是在C 代码请求时可以存储转换后的表示的地方。对于 ASCII 字符串(使用 PyASCIIObject
),UTF-8 数据不需要缓存指针,因为 ASCII 数据本身与 UTF-8 兼容。宽字符缓存仅由不推荐使用的函数使用。
这两个缓存指针永远不会指向同一个地方,因为它们的类型不直接兼容。对于紧凑字符串,它们仅在需要 UTF-8 缓冲区(例如 PyUnicode_AsUTF8AndSize
)或 Py_UNICODE
缓冲区(例如已弃用的 PyUnicode_AS_UNICODE
)的函数被调用时分配。
对于使用已弃用的基于 Py_UNICODE
的 API 创建的字符串,wstr
指针有额外的用途。它指向字符串数据的only 版本,直到在字符串上调用PyUnicode_READY
宏。第一次准备好字符串时,将创建一个新的data
缓冲区,并将字符存储在其中,使用Latin-1、UTF-16 和UTF-32 中可能最紧凑的编码。 wstr
缓冲区将被保留,因为稍后其他想要查找 PY_UNICODE
字符串的已弃用 API 函数可能需要它。
有趣的是,您现在正在询问 CPython 的内部字符串表示,因为有一个讨论 currently ongoing 关于是否可以在即将发布的 Python 版本中删除已弃用的字符串 API 函数和实现细节(如 wchar *
指针) .看起来 Python 3.11.0(预计将于 2022 年发布)可能会发生这种情况,但在此之前计划仍可能发生变化,特别是如果对野外使用的代码的影响比预期的更严重的话。
【讨论】:
以上是关于Python >= 3.3 内部字符串表示的主要内容,如果未能解决你的问题,请参考以下文章