赞
踩
在Python中使用 is 运算符 ,检查两个对象是否引用同一个内存对象。注意在 Python3.8 版本之后,需要使用 == 来判断两个对象是否相等。
"python" == 'python' # true
1==2 # false
"Python" == 'python' # false
在 CPython 中,字符串的引用被一个名为 interned 的 python字典所存储,访问和管理。该字典在第一调用字符串驻留时,被延迟的初始化,并持有全部已驻留字符串对象的引用。
在 CPython 中,负责驻留字符串的核心函数是 PyUnicode_InternInplace 它定义在 unicodeobject.c 中,当调用时,它会创建一个准备容纳所有驻留字符串的字典 Interned , 然后登记入参中的对象,然后另其键和值都使用相同的对象引用
void PyUnicode_InternInplace(PyObject **p)
{
PyObject *s = p;
........
// Lazing build the dicrionary to hold interned strings
if (interned ==NULL) {
interned = PyDict_New();
if (interned ==NULL)
{
PyErr_Clear();
return;
}
}
PyObject *t;
// make an entry to the interned dictionary for the given object
t = PyDict_SetDefault(interned, s, s);
......
// set the state of the string to be INTERNED
_PyUnicode_STATE(s).interned = SSTATE_INTERNED_MORTAL;
}
清理函数从 interned 字典中遍历所有的字符串,调整这些对象的引用计数,并把它们标记为 NOT_INTERNED, 使其被垃圾回收,一旦所有的字符串被标记为 NOT_INTERNED,则 interned 字典会被清空并删除。
这个清理函数就是 _PyUnicode_ClearInterned ,在 unicodeobject.c 中定义
void _PyUnicode_ClearInterned(PyThreadState *tstate)
{
// Get all the keys to the interned dictionary
PyObject *keys = PyDict_Keys(interned);
.......
// Interned Unicode strings are not forcibly deallocated
// rather ,we give them their stolen references back
// and then clear and DECREF the interned dict
for(Py_ssize_t i = 0; i< n; i++)
{
PyObject *s = PyList_GET_ITEM(keys,i);
.....
switch (PyUnicode_CHECK_INTERNED(s)){
case SSTATE_INTERNED_IMMORTAL:
Py_SET_REFCNT(s,Py_REFCNT(s)+1);
break;
case SSTATE_INTERNED_MORTAL:
// Restore the two references(key and balue) ignored
// by PyUnicode_InterInPlace()
Py_SET_REFCNT(s,Py_REFCNT(s) +2);
break;
case SSTATE_NOTINTERNED:
default:
Py_UNREACHABLE();
}
// making the string to be NOT_INTERNED
_PyUnicode_STATE(s).interned = SSTATE_NOT_INTERNED;
}
// decreasing the refernece to the initialized and
// access可以是object
Py_DECREF(keys);
// clearing the dictionary
PyDict_Clear(interned);
// clearing the object interned
Py_CLEAR(interned);
}
这一小节主要讲:Python会驻留哪些字符串
CPython 对常量(例如函数名,变量名,字符串字面量等)执行字符串驻留。
CPthon 还会驻留任何字典对象的字符串键
CPython中对象的属性可以通过 setattr 函数显式地设置,也可以作为类成员的一部分隐式的设置,或者在其数据类型中定义。
CPython会驻留所有这些属性名,以便实现快速的查找。
Python还支持通过 sys模块中的 intern 函数进行显示地字符串驻留。
只有在编译期的字符串会被驻留,解释时或编译时指定的字符串会被驻留,而动态创建的字符串则不会
驻留(interning):实际上是共享字符串字面量的一种优化措施,CPython还会在小的整数上采用这种技术,防止重复创建“热门”数字:如 0 ,-1,42,但是注意 CPython并不会驻留所有字符串和整数,而且驻留条件的细节,也并没有文档说明
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。