|
Python中的字符串对象
在Python中PyStringObject是对字符串对象的实现。PyStringObject是一个变长对象,而且是一个不可变对象。
PyStringObject对象的定义如下:
typedef struct
{
PyObject_VAR_HEAD
Long ob_shash ;
int ob_sstate ;
char ob_sval[1] ;
} ;
Ob_shash 缓存该对象的hash值,ob_shash的初始值为-1,这个hash值的作用我现在还不是很清楚。
另外看下PyStringObject对象的类型对象PyString_Type
PyTypeObject PyString_Type = {
PyObject_HEAD_INIT(&PyType_Type) ;
0, /*tp_size*/
“str”, /*tp_name*/
Sizeof(PyStringObject), /*tp_basicsize*/
Sizeof(char), /*tp_itemsize*/
…..
String_new, /*tp_new */
PyObject_Del , /*tp_free*/
}
可以看到PyStringObject中tp_itemsize被设置为sizeof(char),对于变长对象这个域是必须要指定的,它指定了变长对象保存的元素的单位长度。tp_itemsize和ob_size共同决定了应该额外申请的空间的大小。
Python提供了两种路径,从C中原生的字符串创建PyStringObject对象。
一种是PyString_FromString( const char *str) (1)
另一种是PyString_FromStringAndSize( const char * str, Py_ssize_t size) (2)
这两种的区别是(1)必须提供以‘\0’结尾的字符串,(2)不需要,因为(2)中提供字符串的长度。
看下源码:
PyObject * PyString_FromString(const char * str)
{
Register size_t size ;
Register PyStringObject *op ;
Size = strlen(str) ;
If( size > PY_SSIZE_T_MAX-sizeof(PyStringObject))
{
/* PY_SSIZE_T_MAX是一个与系统有关的值,在win32中被设置为2147483647,大约2G*/
PyErr_SetString( PyExc_OverflowError , “ddd”) ;
Return NULL ;
}
/* 检查是否为一个空字符串创建PyStringObject对象,Python中幷不是为所有的空字符创建PyStringObject对象,在Python中有个PyStringObject对象指针nullstring, 如果第一次在空字符串的基础上创建PyStringObject, 此时nullstring为空,python就会为这个空字符创建PyStringObject对象, 将这个PyStringObject对象通过Intern机制进行共享,然后将nullstring指向这个PyStringObject对象。
如果检查到需要为一个空的字符串创建PyStringObject对象,如果nullstring不为空,就会直接返回nullstring指向的对象*/
If( size = 0 &&(op=nullstring) != NULL )
{
Py_INCREF(op) ;
Return (PyObject*)op ;
}
//处理单个字符
/* 我们前面看到Python为小整数对象设计了缓冲池,Python也为一个字节的字符对应的PyStringObject对象设计了缓冲池,即static PyStringObject * characters[UCHAR_MAX+1],
UCHAR_MAX是一个与系统有关的常量,在win32中是oxff , 小整数对象池是在Python进行运行环境的初始化时创建的,而字符对象池是以静态变量的形式存在的,Python初始化完成之后,缓冲池中的所有PyStringObject指针都为空。*/
If( size==1&&(op=characters[*str&UCHAR_MAX]) != NULL)
{
Return (Python *)op ;
}
//创建Python对象,幷初始化
op = (PyStringObject*)PyObject_MALLOC(sizeof(PyStringObject)+size) ;
if( op == NULL )
return PyErr_NoMemory();
//初始化ob_refcnt = 1 , ob_type, ob_size
PyObject_INIT_VAR(op,&PyString_Type,size) ;
op->ob_shash = -1 ;
op->ob_sstate = SSTATE_NOT_INTERNED ;
Py_MEMCPY(op->ob_sval, str,size+1) ;
if( size == 0 )
{
PyObject *t = (PyObject*)op ;
PyString_InternInPlace(&t) ;//将PyStringObject对象通过Intern机制共享
Op = (PyStringObject *)t ;
nullstring = op ;
Py_INCREF(op) ; // ob_refcnt = 2
}
Else if( size == 1)
{
PyObject *t = (PyObject*)op ;
PyString_InTernInPlace(&t) ;
Op = (PyStringObject *)t ;
Characters[*str&UCHAR_MAX] = op ;
Py_INCREF(op) ;
}
Return (PyObject *)op ;
}
PyObject * PyString_FromStringAndSize( const char * str, Py_ssize_t size )
{
Register PyStringObject *op ;
If( size PY_SSIZE_MAX – sizeof(PyStringObject) )
{
PyErr_SetString(PyExc_OverflowError, “string is too large”) ;
}
//创建PyStringObject对象幷初始化
Op = (PyStringObject*)PyObject_MALLOC(sizeof(PyStringObject)+size) ;
If( op == NULL )
Return PyErr_NoMemory() ;
PyObject_INIT_VAR(op , &PyString_Type , size ) ;
op->ob_shash = -1 ;
op->ob_sstate = SSTATE_NOT_INTERNED ;
if( str != NULL )
Py_MEMCPY(op->ob_sval, str , size) ;
Op->ob_sval[size] = ‘\0’ ;
if( size == 0 )
{
PyObject *t = (PyObject*)op ;
PyString_InternInPlace(&t) ;//将PyStringObject对象通过Intern机制共享
Op = (PyStringObject *)t ;
nullstring = op ;
Py_INCREF(op) ; // ob_refcnt = 2
}
Else if( size == 1)
{
PyObject *t = (PyObject*)op ;
PyString_InTernInPlace(&t) ;
Op = (PyStringObject *)t ;
Characters[*str&UCHAR_MAX] = op ;
Py_INCREF(op) ;
}
Return (PyObject *)op ;
}
现在看下 PyString_InternInPlace( PyObject **p)的源码
void PyString_InternInPlace(PyObject **p)
{
Register PyStringObject *s = (PyStringObject*)(*p) ;
PyObject *t ;
//检查传入的对象是否是PyStringObject对象
If( s == NULL || !PyString_Check(s))
Py_FatalError(“PyString_InternInPlace:strings only please!”);
If( !PyString_CheckExact(s))
Return:
If( PyString_CHECK_INTERNED(s))
Return ;
If( Interned == NULL )
{
/* 在PyDict_New中创建一个PyDictObject对象,幷用PyObject 对象指针interned指向它,在Python中,interned被定义为静态PyObject对象指针 ,被初始化为NULL*/
Interned = PyDict_New() ;
If( Interned == NULL)
{
PyErr_Clear() ;
Return ;
}
t = PyDict_GetItem(interned,(PyObject*)s) ;
//该对象已被interned过,返回被interned过的对象
if(t)
{
Py_INCREF(t) ;
Py_DECREF(*p) ;
*p = t ;
Return ;
}
If( PyDict_SetItem(interned,(PyObject*)s,(PyObject*)s)ob_refcnt -=2 ; (4)
PyString_CHECK_INTERNED(s) = SSTATER_INTERNED_MORNAL ;
}
在(3)处,在将一个PyStringObject对象的PyObject指针s作为key和value添加到interned,PyDictObject对象会通过这两个指针对s的引用计数进行两次加1。
由于Python的设计者规定在interned中a的指针不能视为对对象a的引用。
故在(4)有两次减减操作。
|
|
|