本文主要阐述三个问题:
1.PyStringObject(字符串对象)
2.PyString_Type(字符串对象的类型)
3.创建字符串对象
一、PyStringObject(字符串对象)
[stringobject.h] typedef struct { PyObject_VAR_HEAD long ob_shash; int ob_sstate; char ob_sval[1];
/* Invariants: * ob_sval contains space for 'ob_size+1' elements. * ob_sval[ob_size] == 0. * ob_shash is the hash of the string or -1 if not computed yet. * ob_sstate != 0 iff the string object is in stringobject.c's * 'interned' dictionary; in this case the two references * from 'interned' to this object are *not counted* in ob_refcnt. */ } PyStringObject;
1 #define PyObject_VAR_HEAD \ 2 PyObject_HEAD \ 3 Py_ssize_t ob_size;
PyStringObject是一个拥有可变长度内存的对象。比如:“hi”和"python"是两个不同的PyStringObject对象,其内部所需的保存字符串内容的内存空间显然是不一样的。
同时PyStringObject对象又是一个不变对象。为什么这样说呢?当创建一个PyStringObject对象之后,该对象内部维护的字符串就不能改变了。也就是在创建字符串对象时,其内存是不定的,在这个层面上,它是一个可变对象;但是一旦字符串创建后,其长度就不能改变了,在这个层面,它又是不变对象。
PyObject_VAR_HEAD,其中有一个ob_size变量保存对象维护的可变长度内存的大小。
char ob_sval[1];//作为一个字符指针指向一段内存,这段内存保存着字符串对象维护的实际字符串。
内存的实际长度(字节),由ob_size维护,这是python所有变长对象的实现机制。比如PyStringObject对象“python”,ob_size值就是6。ob_sval指向一段长度为ob_size+1个字节的内存,因为在C语言中,字符串结尾的标志位'\0',而存在這样一种可能,字符串 中间就有'\0',因此,在pytho中,判断字符结束的条件是ob_sval[ob_size] == '\0'。
ob_shash作用是缓存该对象的hash值,这样就避免了每一次重新计算该字符串对象的hash值。如果一个对象还没没有计算过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 = Py_SIZE(a); if (len == 0) { a->ob_shash = 0; return 0; } p = (unsigned char *) a->ob_sval; x = _Py_HashSecret.prefix; x ^= *p << 7; while (--len >= 0) x = (1000003*x) ^ *p++; x ^= Py_SIZE(a); x ^= _Py_HashSecret.suffix; if (x == -1) x = -2; a->ob_shash = x; return x; }