fateame 发表于 2015-4-28 05:51:31

Python中的字符串对象

                          Python中的字符串对象
  
  在Python中PyStringObject是对字符串对象的实现。PyStringObject是一个变长对象,而且是一个不可变对象。
  PyStringObject对象的定义如下:
  typedef struct
  {
      PyObject_VAR_HEAD
      Long ob_shash ;
     int ob_sstate ;
     char ob_sval ;
  } ;
  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是一个与系统有关的常量,在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 )
  {
  RegisterPyStringObject *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 = ‘\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)有两次减减操作。
  
  
  
  
  
页: [1]
查看完整版本: Python中的字符串对象