字符串对象是Python变长对象中的不可变对象,对象的长度在对象创建时才能被确定,但对象创建之后其所维护的数据就不能再改变。对于PyStringObject的定义如下:
[stringobject.h]
typedef struct{
PyObject_VAR_HEAD
long ob_shash;
int ob_sstate;
char ob_sval[1];/*作为字符指针指向对象所维护的实际字符串所在内存*/
} PyStringObject;
由于字符串的长度由PyObject_VAR_HEAD中的ob_size字段来维护,因此PyStringObject所维护的字符串对象中间可能出现字符‘\0',但是同C中的字符串一样,PyStringObject内部维护的字符串必须以‘\0'结尾,因此ob_sval指向的是一段包含ob_size+1个元素的内存,且ob_sval[ob_size]=‘\0'。
PyStringObject对应的类型对象PyString_Type定义如下
[stringobject.c]
PyTypeObject PyString_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"str",
sizeof(PyStringObject),
sizeof(char), /*tp_itemsize, 变长对象所保存的元素的单位长度*/
...
(reprfunc)string_repr,
&string_as_number, /*tp_as_number, 字符串对象支持数值操作*/
&string_as_sequence, /*tp_as_sequence, 支持序列操作*/
...
string_new, /*tp_new*/
PyObject_Del, /*tp_free*/
};
字符缓冲池
字符串对象体系中的字符缓冲池是以静态变量的形式存在着,不同于小整数的缓冲池是在Python初始化时被创建的,字符缓冲池中的所有PyStringObject指针都为空。[stringobject.c]
PyObject* PyString_FromString(const char *str)
{
register size_t size;
register PyStringObject *op;
size = strlen(str);
if (size > PY_SSIZE_T_MAX){
return NULL;
}
if (size==0 && (op=nullstring)!=NULL){
retrun (PyObject *)op;
if(size==1 && (op = characters[*str & UCHAR_MAX]) != NULL){
return (PyObject *) op;
op=(PyStringObject *)PyObject_MALLOC(sizeof(PyStringObject)+size);
...
memcpy(op->ob_sval, str, size+1);
...
return (PyObject *) op;
}
以PyString_FromString为例,要创建一个字符串对象,首先传入的参数必须是一个指向以NULL('\0')结尾的字符串的指针,先检查对应字符数组的长度,若长度大于定义的最大值,Python将不会创建对应的字符串对象,然后根据字符数组的长度大致分为三种情况,一种是传入的字符串是一个空串,对于空串,Python对于首次的请求会创建一个空字符串的PyStringObject对象,并将这个对象通过intern机制进行共享,然后将nullstring指向这个被共享的对象,以便在第二次创建空字符串的请求时,直接返回nullstring的引用即可,不再创建新的对象;当字符数组长度等于1时,首先判断缓冲池中是否已存在该字符对象,若有,则直接返回;最后一种情况是字符串不为空且长度大于1或者长度为1但不在字符对象的缓冲池中,则需要申请相应的内存空间(size=sizeof(PyStringObject)+sizeof(str)),这个空间不仅包含PyStringObject所需内存也包含字符数组内的元素所需的额外内存
&spm=1001.2101.3001.5002&articleId=19514827&d=1&t=3&u=879a7db01f1b4d8fbbe392eabd707c15)
1万+

被折叠的 条评论
为什么被折叠?



