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<0)

   PyErr_SetString(PyExc_SystemError, “Negative size passed to PyString_From”) ;

// 处理null string

If( size == 0 && (op = nullstring) != NULL )

{

   Py_INCREF(op) ;

   Return (PyObject*)op ;

}

//处理字符

If( size == 1 && str != NULL&&(op=characters[*str&UCHAR_MAX] != NULL )

{

   Py_INCREF(op) ;

   Return (PyObject*)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)<0)         (3)

{

    PyErr_Clear();

    Return ;

}

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)有两次减减操作。  

 

 

 

 

 

posted on 2010-06-04 13:52  liuze  阅读(2573)  评论(0编辑  收藏  举报