PyStingObject对象的intern机制
根据之前讨论的PyStringObject对象创建的方式,假设创建一个String对象a,其表示的字符串是“Python”, 随后若再一次为字符串"Python“创建一个String对象,通常情况下,Python会重新申请一个内存来创建一个新的PyStringObject对象b,a与b是完全不同的两个对象,各占一段内存,尽管其内部维护的字符数组是完全相同的,那以此类推,若在程序中需要创建100个"Python"字符串对象则必然会浪费大量内存。
因此Python为PyStringObject对象引入了intern机制,目的就是对被intern之后的字符串,在整个python的运行期间,系统中都只有唯一的一个与字符串对应的PyStringObject对象,以上一个”Python“为例,如果对于对象a应用了intern机制,那在其之后创建b时,Python会在系统中记录的已经被intern机制处理了的PyStringObject对象中查找,如果发现该字符数组对应的PyStringObject对象已经存在了,最终会返回该对象的引用,从而可以节省空间,这样也使得当需要判断两个被intern的PyStringObject对象是否相同时,只需要简单地检查它们对应的PyObject* 是否相同即可。[stringobject.c]
PyObject * PyString_FromString(const char *str)
{
register size_t size;
register PyStringObject *op;
.....//创建PyStringObject对象;
// intern长度较短的PyStringObject对象
if(size == 0) {
PyObject *t = (PyObject *)op;
PyString_InternInPlace(&t);
op = (PyStringObject *)t;
nullstring = op;
} else if (size == 1) {
PyObject *t = (PyObject *)op;
PyString_InternInPlace(&t);
op = (PyStringObject *)t;
characters[*str & UCHAR_MAX] = op;
}
return (PyObject *) op;
}
由此看出,PyString_InternInPlace正是负责完成对一个对象进行intern操作的函数。
[stringobject.c]
void PyString_InternInPlace(PyObject **p)
{
register PyStringObject *s = (PyStringObject *)(*p);
PyObject *t;
//对PyStringObject进行类型和状态检查
if (!PyString_CheckExact(s))
return;
if (PyString_CHECK_INTERNED(s))
return;
//创建记录经intern机制处理后的PyStringObject的dict
if (interned == NULL) {
interned = PyDict_New();
}
//检查对象是否存在对应的intern后的PyStringObject对象
t = PyDict_GetItem(interned, (PyObject *)s);
if (t) {
Py_INCREF(t);
Py_DECREF(*p);
*p = t;
return;
}
//在interned中记录检查PyStringObject对象, 调整计数及intern状态标志
PyDict_SetItem(interned, (PyObject *)s, (PyObject *)s);
s->ob_refcnt -=2;
PyString_CHECK_INTERNED(s) = SSTATE_INTERNED_MORTAl;
}
PyString_InternInPlace会进行一系列操作,包括: