目录
1.PyStringObject与PyString_Type
1.PyStringObject与PyString_Type
在python中,PyStringObject是对字符串对象的实现,PyStringObject是一个拥有可变长度内存的对象,这一点容易理解,因为“Hi”和“Lian”创建的PyStringObject其内部需要的内存空间不一样大小。同时,PyStringObject也是一个不可变对象,当创建一个PyStringObject对象后,其内部维护的字符串不能再发生改变。
PyStringObject的定义:
typedef struct {
PyObject_VAR_HEAD
long ob_shash;
int ob_sstate;
char ob_sval[1];
} PyStringObject;
在PyStringObject定义我们可以看到,它的头部实际是一个PyObject_VAR_HEAD,其中有一个ob_size变量保存着对象中维护的可变长度内存的大小。ob_sval是一个字符数组,但是它是作为一个字符指针指向一段内存的,这段内存保存着这个字符串对象维护的实际字符串。
同c中的字符串一样,PyStringObject内部维护的字符串在末尾以‘\0’结尾,所以ob_sval指向的是一段长度为ob_size+1个字节的内存,且ob_sval[ob_szie] ='\0'.
ob_shash的作用是缓存对象的hash值,这样可以避免每一次都要重新计算该字符串对象的hash值,如果PyStringObject还没被计算过hash值,那么ob_shash的初始化值为-1。计算一个字符串对象的hash值采用的算法:
static long string_hash(PyStringObject *a)
{
register Py_ssize_t len;
register unsigned char *p;
register long x;
if (a->ob_shash != -1)
return a->ob_shash;
len = a->ob_size;
p = (unsigned char *) a->ob_sval;
x = *p << 7;
while (--len >= 0)
x = (1000003*x) ^ *p++;
x ^= a->ob_size;
if (x == -1)
x = -2;
a->ob_shash = x;
return x;
}
ob_sstate变量标记该对象是否已经过intern机制处理,intern机制是这节非常重要的点。
PyStringObject的类型对象是PyString_Type:
PyTypeObject PyString_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"str",
sizeof(PyStringObject),
sizeof(char),
string_repr, /* tp_repr */
&string_as_number, /* tp_as_number */
&string_as_sequence, /* tp_as_sequence */
&string_as_mapping, /* tp_as_mapping */
(hashfunc)string_hash, /* tp_hash */
string_methods, /* tp_methods */
&PyBaseString_Type, /* tp_base */
.......
string_new, /* tp_new */
PyObject_Del, /* tp_free */
};
我们可以看到,tp_itemsize被设置为sizeof(char),对于python中任意变长对象,tp_itemsize这个域必须设置,它指明了由变长对象保存的元素的单位长度,tp_itemsize和ob_size共同决定了还需要额外申请的内存大小。
2.PyStringObject的创建
python提供了两条路径从c中原生的字符串创建PyStringObject对象:
PyAPI_FUNC(PyObject *) PyString_FromStringAndSize(const char *, Py_ssize_t);
PyAPI_FUNC(PyObject *) PyString_FromString(const char *);
我们先查看PyString_FromString的源码:
PyObject *PyString_FromString(const char *str)
{
register size_t size;
register PyStringObject *op;