PyStringObject效率相关的问题
在Python中又一个举足轻重的问题:字符串连接问题。字符串连接有两种方式:(1)通过“+”对字符串进行连接
(2)利用PyStringObject对象的join操作来对存储在list或tuple中的一组
PyStringObject对象进行连接操作。
(1)法效率比较低,因为Python中字符串对象是一个不可变的对象,当我们进行“+”操作时,我们就得从新申请一个新的PyStringObject对象。如果我们要进行N个字符串对象的连接,我们我要进行N-1次内存的申请和内存搬运的工作,显然,效率是十分底下的。使用(2)法可解决这个问题。
下面看下源码:
Static PyObject * string_concat(register PyStringObject *a, register PyStringObject *bb)
{
Register Py_ssize_t size ;
Register PyStringObject *op ;
If( ! PyString_Check(bb))
{
PyErr_Format(PyExc_TypeError,“cannot concatenate ‘str’and
‘%.200s’objects”, bb->ob_type->tp_name);
Return NULL ;
}
# define b ((PyStringObject*)bb)
//如果a或bb是指向空字符串对象的指针
If( (a->ob_size==0 || b->ob_size==0)&&
PyString_CheckExact(a)&&PyString_CheckExact(b))
{
If( a->ob_size == 0 )
{
Py_INCREF(bb) ;
Return bb ;
}
Py_INCREF(a) ;
Return (PyObject*)a;
}
Size = a->ob_size + b->ob_size ;//字符串连接后的长度size
If( a->size<0||b->size<0||a->ob_size+b->ob_size > PY_SSIZE_T_MAX)
{
PyErr_SetString(PyExc_OverflowError, “string are too large”) ;
Return NULL ;
}
/*创建新的PyStringObject对象,其维护的用于存储字符的内存长度为
Size */
Op = (PyStringObject*)PyObject_MALLOC(sizeof(PyStringObject)+size);
PyObject_INIT_VAR(op,&PyString_Type,size);
Op->ob_shash = -1 ;
Op->ob_sstate = SSTATE_NOT_INTERNED ;
将a和b中的字符拷贝到新创建的PyStringObject中
Memcpy(op->ob_sval, a->ob_sval , a->ob_size) ;
Memcpy(op->ob_sval+a->ob_size , b->ob_sval , b->ob_size) ;
Op->ob_sval[size] = ‘\0’;
Return (PyObject*)op ;
# undif b ;
}
Static PyObject * string_join(PyStringObject *self,PyObject *orig)
{
Char *sep = PyString_AS_STRING(self) ;
Const Py_ssize_t seplen = PyString_GET_SIZE(self) ;
PyObject *res = NULL ;
Char *p ;
Py_ssize_t seqlen = 0 ;
Size_t sz=0 ;
Py_ssize_t i ;
PyObject *seq, *item;
Seq = PySequence_Fast(orig, “”);
If( seq == NULL )
{
Return NULL ;
}
Seqlen = PySequence_Size(seq) ;
If( seqlen == 0 )
{
Py_DECREF(seq) ;
Return PyString_FromString(“”);
}
If( seqlen == 1)
{
Item = PySequence_Fast_ITEM(seq,0) ;
If( PyString_CheckExact(item)||PyUnicode_CheckExact(item))
{
Py_INCREF(item) ;
Py_DECREF(seq) ;
Return item ;
}
}
For( i = 0 ; i < seqlen ; i++)
{
Const size_t old_sz = sz ;
Item = PySequence_Fast_GET_ITEM(seq,i) ;
If( ! PyString_Check(item))
{
PyErr_Format(PyExc_TypeError,“sequence item %zd:expected string,”) ;
Py_DECREF(seq) ;
Return NULL ;
}
Sz += PyString_GET_SIZE(item) ;
If( I != 0 )
Sz += seqlen ;
Res = PyString_FromStringAndSize((char*)NULL , sz) ;
If( res == NULL)
{
Py_DECREF(seq) ;
Return NULL ;
}
P = PyString_AS_STRING(res) ;
For( I = 0 ; I < seqlen; ++ i)
{
Size_t n ;
Item = PySeqence_Fast_GET_ITEM(seq, i) ;
n = PyString_GET_SIZE(item);
Py_MEMCPY(p ,PyString_AS_STRING(item) , n) ;
P+=n ;
If( I < seqlen-1)
{
Py_MEMCPY(p,seq,seplen) ;
P+=sepen ;
}
}
Py_DECREF(seq) ;
Return res;
}