Python 3.x 中字符串的内部表示是啥
Posted
技术标签:
【中文标题】Python 3.x 中字符串的内部表示是啥【英文标题】:What is internal representation of string in Python 3.xPython 3.x 中字符串的内部表示是什么 【发布时间】:2010-12-22 17:31:15 【问题描述】:在 Python 3.x 中,字符串由 Unicode 序数项组成。 (请参阅下面语言参考中的引文。)Unicode 字符串的内部表示是什么?是 UTF-16 吗?
字符串对象的项目是 Unicode 代码单元。一个 Unicode 代码 单位由字符串对象表示 一件物品,可以容纳一个 表示一个 16 位或 32 位值 Unicode 序数(最大值 序数在 sys.maxunicode,取决于如何 Python 在编译时配置)。 代理对可能存在于 Unicode 对象,并将被报告 作为两个单独的项目。
【问题讨论】:
【参考方案1】:python内部编码中的每个字符都被编码为4个字节。
>>> import array; s = 'Привет мир!'; b = array.array('u', s).tobytes(); print(b); print(len(s) * 4 == len(b))
b'\x1f\x04\x00\x00@\x04\x00\x008\x04\x00\x002\x04\x00\x005\x04\x00\x00B\x04\x00\x00 \x00\x00\x00<\x04\x00\x008\x04\x00\x00@\x04\x00\x00!\x00\x00\x00'
True
>>> import array; s = 'test'; b = array.array('u', s).tobytes(); print(b); print(len(s) * 4 == len(b))
b't\x00\x00\x00e\x00\x00\x00s\x00\x00\x00t\x00\x00\x00'
True
>>>
【讨论】:
你能详细说明这段代码的作用吗?尤其是不是英文的部分Привет мир!
那篇俄语文章用于描述当您使用 ASCII 以外的字符时会发生什么。顺便说一句,它是“你好世界!”俄语。【参考方案2】:
内部表示从 latin-1、UCS-2 到 UCS-4 不等 . UCS 表示表示长度为 2 或 4 个字节,并且 unicode 代码单元在数字上等于相应的代码点。我们可以通过查找代码单元大小的变化来检查这一点。
显示它们的范围从 latin-1 的 1 个字节到 UCS-4 的 4 个字节:
>>> getsizeof('')
49
>>> getsizeof('a') #------------------ + 1 byte as the representaion here is latin-1
50
>>> getsizeof('\U0010ffff')
80
>>> getsizeof('\U0010ffff\U0010ffff') # + 4 bytes as the representation here is UCS-4
84
我们可以检查开始的表示确实是 latin-1 而不是 UTF-8,因为对 2 字节代码单元的更改发生在字节边界而不是 ''\U0000007f'
- '\U00000080'
边界,如 UTF- 8:
>>> getsizeof('\U0000007f')
50
>>> getsizeof('\U00000080') #----------The size of the string changes at \x74 - \x80 boundary but..
74
>>> getsizeof('\U00000080\U00000080') # ..the size of the code-unit is still one. so not UTF-8
75
>>> getsizeof('\U000000ff')
74
>>> getsizeof('\U000000ff\U000000ff')# (+1 byte)
75
>>> getsizeof('\U00000100')
76
>>> getsizeof('\U00000100\U00000100') # Size change at byte boundary(+2 bytes). Rep is UCS-2.
78
>>> getsizeof('\U0000ffff')
76
>>> getsizeof('\U0000ffff\U0000ffff') # (+ 2 bytes)
78
>>> getsizeof('\U00010000')
80
>>> getsizeof('\U00010000\U00010000') # (+ 4 bytes) Thes size of the code unit changes to 4 at byte boundary again.
84
【讨论】:
【参考方案3】:在 Python 3.3 及更高版本中,字符串的内部表示将取决于字符串,可以是 latin-1、UCS-2 或 UCS-4 中的任何一种,如 PEP 393 中所述。
对于以前的 Python,内部表示取决于 Python 的构建标志。可以使用标志值 --enable-unicode=ucs2
或 --enable-unicode=ucs4
构建 Python。 ucs2
构建实际上是 use UTF-16 as their internal representation,而 ucs4
构建使用 UCS-4 / UTF-32。
【讨论】:
这是正确答案,应该被接受。【参考方案4】:在Include/unicodeobject.h
中查看 CPython 3.1.5 的源代码:
/* --- Unicode Type ------------------------------------------------------- */
typedef struct
PyObject_HEAD
Py_ssize_t length; /* Length of raw Unicode data in buffer */
Py_UNICODE *str; /* Raw Unicode buffer */
long hash; /* Hash value; -1 if not set */
int state; /* != 0 if interned. In this case the two
* references from the dictionary to this object
* are *not* counted in ob_refcnt. */
PyObject *defenc; /* (Default) Encoded version as Python
string, or NULL; this is used for
implementing the buffer protocol */
PyUnicodeObject;
字符存储为Py_UNICODE
的数组。在大多数平台上,我相信Py_UNICODE
是#define
d 和wchar_t
。
【讨论】:
【参考方案5】:在实现PEP 393 的 Python 3.3 中,内部表示将发生变化。新的表示会选择ascii, latin-1, utf-8, utf-16, utf-32中的一个或几个,一般都是为了得到一个紧凑的表示。
只有在与遗留 API 对话时才会隐式转换为代理对(这些 API 仅存在于 windows 上,其中 wchar_t 是两个字节); Python 字符串将被保留。这是release notes。
【讨论】:
在我看来,PEP 393 表示内部表示是 ASCII、Latin-1 (UCS1)、UCS2 或 UCS4 的最紧凑(给定特定字符串)。即:特别不是 utf-8/16/32。原因:Python 必须是常数时间才能索引到字符串,因此字符必须是统一的大小,UCS 就是这种情况,但 utf 表示不是。 Latin-1 是 ASCII 的超集,因此没有理由将 ASCII 作为选项之一。选项是 (a) 统一 8 位,即 Latin-1,(b) 统一 16 位,即 UCS2,或 (c) 统一 32 位,即 UCS4(与 UTF-32 相同)。值得注意的是 UTF-8 和 UTF-16,它们的每个代码点的位数不统一【参考方案6】:Python 2.X 和 3.X 之间的 Unicode 内部表示没有变化。
绝对不是 UTF-16。 UTF-anything 是一种面向字节的 EXTERNAL 表示。
已为每个代码单元(字符、代理项等)分配了一个范围为 (0, 2 ** 21) 的数字。这被称为它的“序数”。
真的,您引用的文档说明了一切。大多数 Python 二进制文件使用 16 位序数,这将您限制在基本多语言平面(“BMP”),除非您想使用代理(如果您找不到您的头发衬衫并且您的指甲床已经关闭,这很方便)生锈)。为了使用完整的 Unicode 曲目,您更喜欢“宽版本”(32 位宽)。
简而言之,unicode 对象的内部表示是一个 16 位无符号整数数组,或一个 32 位无符号整数数组(仅使用 21 位)。
【讨论】:
“以 16 位整数存储 unicode 代码点”称为“UCS-2”。用 32 位整数做同样的事情是 UCS-4。 @John:我不明白你想说什么。如果它不是“存储 Unicode 代码点的方式”(或更普遍的字符信息),那么什么是编码。是的,我很清楚 UTF-16 是 UCS-2 的现代替代品,但它与您所说的不同。 UTF-16 支持所有的 Unicode,但 UCS-2 只支持 BMP。 “没有变化……”。实际上,请参阅 PEP 393(2010 年 1 月),其中阐明了随后发生的变化,以及此处的另一个答案“内部表示将改变......” 这个答案是错误的,见下面东武的答案。 PEP 393 是在给出这个答案后一个月写的。 “UTF-anything 是一种面向字节的外部表示”。在某些系统中,它也是有效的内部表示。例如,在许多基于 C++ 的系统中,UTF-8 在内部使用,而不仅仅是用于 I/O。 Go 专门使用 UTF-8 作为内部字符串表示。【参考方案7】:我认为,UTF-16(只是 16 位字的序列)与 Python 的字符串对象之间的区别很难判断。
如果 python 编译时使用 Unicode=UCS4 选项,它将在 UTF-32 和 Python 字符串之间进行比较。
因此,最好考虑一下,它们属于不同的类别,尽管您可以相互转换。
【讨论】:
【参考方案8】:这取决于:请参阅here。就内部表示而言,这对于 Python 3 仍然适用。
【讨论】:
以上是关于Python 3.x 中字符串的内部表示是啥的主要内容,如果未能解决你的问题,请参考以下文章