字符串对象是不可变对象,使得字符串对象可以作为dict的键值,但是也使得一些字符串操作的效率大大降低,例如多个字符串的连接操作。
typedef struct {
PyObject_VAR_HEAD
long ob_shash;
int ob_sstate;
char ob_sval[1];
} PyStringObject;
可变对象有一个ob_size保存包含对象的个数,ob_shash就是该字符串对象的hash值,避免重复计算,ob_sval虽然看起来是一个字符数组,实际上是作为一个字符串指针来使用的,指向的是一个ob_size + 1的内存,且ob_sval[ob_size] = '\0',ob_sstate则说明该对象是否经过了intern机制的处理(hash 和 intern机制可提升虚拟机的运行效率 20%),默认:op->ob_shash = -1;op->ob_sstate = SSTATE_NOT_INTERNED
字符串对象创建
PyString_FromString(const char *str)
对于正常的字符串则分配内存,然后复制str的值到新分配的内存中,完毕
PyString_FromStringAndSize(const char *str, int size)
这个函数接受的str可以不用'\0'结尾,具体大小直接按size决定
字符串intern
对空字符串和单字符串的处理
在完成字符串创建之后,对空字符串有一个特殊处理,即当传入的str为一个'\0'的字符串,则都指向python内部已经创建好的nullstring对象;对数组长度为1的,即传入的是'A\0'这样的字符串,放入characters数组中
处理结果:空字符串和单字符 这两种string对象在python运行中持久化
对普通字符串的处理
利用一个名称为interned的dict,来实现名称相同的字符串不用重复在内存中创建,但实现的逻辑为:
仍然创建该字符串对象,然后以该字符串对象为key在dict中查找,如果找到,则把新创建的字符串对象删除,使用原来的,增加引用计数即可
字符串连接
每两个字符串连接,会计算两个字符串的长度和,分配内存,然后复制,如果是n个字符串连接会执行n-1次分配内存再复制的操作,低效
使用join操作,则把列表中的所有字符串取出长度,分配一次内存,然后复制,高效