上一节我们大体认识了 int 对象,在 Python 3 中实际上是以 LongObject 实现的,在 LongObject 的类型定义中,我们根据其类型名称 “int” 确认了这一点。回顾 int 对象的结构:
与 Python 2 不同,Python 3 中实现了任意长度的整数,整数的实际数据是紧跟在 PyVarObjectHead 之后的一个连续内存,从整数对象被创建开始,直到香消玉殒的那一刻,整数的 “值” 与这个整数对象都不会分离,它们是一个整体,无法在不进行内存分配的前提下任意修改整数的值。所以说整数对象是不可变对象,一旦创建就不能再被修改。回顾使用 Python 时,在 dict 类型中要求 key 必须为可 hash 的不可变类型,int 类型便在其中,int 类型不可变的结论符合以往的使用经验。
int 对象还有丰富的内容有待我们探索,不过我暂时不想在具体的细节上消耗太多时间,我希望尽快对 Python 3 有一个宏观肌理的印象,就继续看一下 Python 3 中另一个常见的类型 string 的实现。
String Object 的结构
Python 3 中 Stirng 对象与之前的实现变化比较大,源码中已经没有 stringobject. 的文件,已经被替换为 unicodeobject. 文件,可以在 Objects 和 Includes 目录下找到相关文件。根据 LongObject 的经验,我们首先找到 PyUnicode_Type 的定义:
//Objects/unicodeobject.c:15494
PyTypeObject PyUnicode_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"str", /* tp_name */
sizeof(PyUnicodeObject), /* tp_basicsize */
0, /* tp_itemsize */
/*
*************省略了一些代码*************
*/
unicode_new, /* tp_new */
PyObject_Del, /* tp_free */
};
可以确认 PyUnicode_Type 正是我们要找到 String 类型。
前往 Include/cpython/unicodeobject.h 可以看到 PyUnicodeObject 的具体定义,删除其中的注释:
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; /* Number of bytes in utf8, excluding the
* terminating \0. */
char *utf8; /* UTF-8 representation (null-terminated) */
Py_ssize_t wstr_length; /* Number of code points in wstr, possible
* surrogates count as two code points. */
} PyCompactUnicodeObject;
typedef struct {
PyCompactUnicodeObject _base;
union {
void *any;
Py_UCS1 *latin1;
Py_UCS2 *ucs2;
Py_UCS4 *ucs4;
} data; /* Canonical, smallest-form Unicode buffer */
} PyUnicodeObject;
删掉注释代码量并不多,Python 3 深度支持 Unicode,对比 Python 2,String Object 做了比较大的调整, PyUnicodeObject 通过多层结构支持 ascii 和 unicode,一图胜千言,下面是 PyUnicodeObject 的结构。
实际上一个 PyUnicodeObject 对象是多种类型的复合体,可以表示最简单的 ascii 字符串、紧凑 unicode、unicode 3种字符串。 主要字段的意义:
- length 保存了字符串种 codepoint 数量;
- hash 保存字符串的哈希值,这里也表明字符串是一个不可变对象;
- state 是一些状态标志位,只用了其中 8 位,剩余 24 位补齐,以便对齐到 32 位;
- wstr 真正保存字符串的值,与 C 语言一样,以 '\0' 结束;
PyASCIIObject 构成了 PyUnicodeObject 的主体,注意到 unicode 对象有多个长度、数据字段,明天继续。