字符串对象的项是Unicode代码单元。Unicode代码单元由一个项的字符串对象表示,可以存储表示Unicode序数的16位或32位值(序数的最大值在sys.maxunicode中给出,并且取决于Python在编译时的配置)。代理对可能存在于Unicode对象中,并将报告为两个单独的项。
字符串对象的项是Unicode代码单元。Unicode代码单元由一个项的字符串对象表示,可以存储表示Unicode序数的16位或32位值(序数的最大值在sys.maxunicode中给出,并且取决于Python在编译时的配置)。代理对可能存在于Unicode对象中,并将报告为两个单独的项。
--enable-unicode=ucs2
或--enable-unicode=ucs4
进行构建。ucs2
构建实际上使用UTF-16作为其内部表示,而ucs4
构建使用UCS-4 / UTF-32。查看CPython 3.1.5的源代码,在Include/unicodeobject.h
中:
/* --- 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
是用wchar_t
进行#define
的。
内部表示形式从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字节代码单元的变化发生在字节边界而不是在UTF-8中的''\U0000007f'
-'\U00000080'
边界:
>>> 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
>>> 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
>>>
Привет мир!
。 - shripal mehta我认为,很难判断UTF-16和Python的字符串对象之间的区别,因为UTF-16只是一系列16位字,而Python的字符串对象则不同。
如果Python编译时使用了Unicode=UCS4选项,则将比较UTF-32和Python字符串。
因此,最好考虑它们属于不同的类别,尽管可以相互转换。
Python 2.X和3.X之间的Unicode内部表示没有任何变化。
它绝对不是UTF-16。UTF-anything是面向字节的外部表示。
每个代码单元(字符,代理等)都被分配了一个来自range(0,2 ** 21)的数字。这被称为它的“序数”。
实际上,您引用的文档已经说明了一切。大多数Python二进制文件使用16位序数,这将限制您仅能使用基本多语言平面(“BMP”),除非您想要使用代理(如果您找不到头发衬衫并且您的钉床正在去锈)。要使用完整的Unicode字符集,您需要选择“宽构建”(32位宽)。
简而言之,在unicode对象中的内部表示是一个16位无符号整数数组,或者是一个32位无符号整数数组(仅使用21位)。