设为首页 收藏本站
查看: 1180|回复: 0

[经验分享] Python中的字符串对象

[复制链接]

尚未签到

发表于 2015-4-28 05:51:31 | 显示全部楼层 |阅读模式
                          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)有两次减减操作。  
  
  
  
  
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-61288-1-1.html 上篇帖子: python的安装和配置 下篇帖子: 用Linux的iptables和Python模拟广域网
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表