typedef struct {
PyObject_VAR_HEAD
long ob_shash; // 记录该字符串对象的hash值,避免重复计算
int ob_sstate; // 对象状态,是否interned
char ob_sval[1]; // 实际存储的是字符串值的指针
} PyStringObject;
字符串对象模型如下,与《python源码剖析》中稍许不同
1、PyStringObject对象的创建
创建 PyStirngObjecet 时,先在对象池中查找,有则返回,无则创建并加入缓冲池。对象缓冲池为即为interned,实质为字典对象dict_object。
PyString_FromString(const char *str) // 有删减
{
register size_t size;
register PyStringObject *op;
size = strlen(str);
if (size == 0 && (op = nullstring) != NULL) {
return (PyObject *)op;
if (size == 1 && (op = characters[*str & UCHAR_MAX]) != NULL) {
return (PyObject *)op;
op = (PyStringObject *)PyObject_MALLOC(PyStringObject_SIZE + size); // 创建对象
……
/* 将长度较短PyStringObject对象加入对象池 */
if (size == 0)
……
else if (size == 1)
……
return (PyObject *) op;
}
size为0返回nullstring,size为1在字符缓冲池中查找并返回。
其实更长的字符串也共享了对象池,却没有找到代码。
2、Intern机制
PyString_InternInPlace(PyObject **p){ // 有删减
PyStringObject *s = (PyStringObject *)(*p);
……
if (interned == NULL)
interned = PyDict_New();
t = PyDict_GetItem(interned, (PyObject *)s);
if (PyDict_SetItem(interned, (PyObject *)s, (PyObject *)s) < 0)
……
}
由上函数可以看出,对象池interned实质为字典对象,并且key与value都是同一个PyStringObject对象的指针。并且在查找前需要创建临时PyStringObject对象作为key。
3、字符缓冲池
static PyStringObject *characters[UCHAR_MAX + 1];
characters[]中存储了256个单字符的PyStringObject对象的指针。
characters[*str & UCHAR_MAX] // 此语句即可直接定位到 str 对象的指针