5. Python3源码—字符串(str)对象

作者: 阿里云云栖号 | 来源:发表于2018-06-11 15:18 被阅读118次

5.1. 字符串对象

字符串对象是“变长对象”。

5.1.1. Python中的创建

Python中字符串(strs)对象最重要的创建方法为PyUnicode_DecodeUTF8Stateful,如下Python语句最终会调用到PyUnicode_DecodeUTF8Stateful:

5.1.2. PyUnicode_DecodeUTF8Stateful的C调用栈

词法解析,最终调到PyUnicode_DecodeUTF8Stateful,调用顺序如下:

5.1.3. PyUnicode_DecodeUTF8Stateful源码

可以看到:

1、空串缓存:空串(unicode_empty)为同一个地址,第二次需要空串时,只是将计数加1,在_PyUnicodeWriter_Finish中实现空串缓存。

2、字符缓冲池:字符(unicode_latin1)为同一个地址,第二次需要该字符时,只是将计数加1,在get_latin1_char中实现字符缓存。

5.2. 常量字符串池

由上例可以看出Python对常量字符串做了缓存。缓存的关键性实现在PyUnicode_InternInPlace方法中。

5.2.1. PyUnicode_InternInPlace的C调用堆栈

5.2.2. PyUnicode_InternInPlace源码

其中最关键的方法为PyDict_SetDefault,该方法存在于字典对象dictobject.c中。如果没有相同的key(此处为s),则返回defaultobject(此处也为s),否则如果有相同的key则返回对应的value。所以如果t与s不同,则说明字典中有相应的key,此时将t的计数加1,并且将之前常量字符串的对象指向t。

如此一来,常量字符串的对象地址就一致了,此时s的计数会被消除,如果s的计数为0,则会被释放。值得注意的是,常量字符串的对象每次仍旧会被多分配一次内存,只是如果之前有分配过,且如果此次分配的对象计数为0,则会被释放。

有些情况下(字符串包含非0-9a-zA-Z)不会放到字典里,这时候可以通过sys.intern进行性能优化:

具体可以参考:memory - What does python sys.intern do, and when should it be used? - Stack Overflow

5.3. 字符串对象的特性

支持tp_as_number、tp_as_sequence、tp_as_mapping这三种操作。

5.3.1. 数值操作

5.3.2. 序列操作

因为没有实现PySequenceMethods中的设置方法,所以字符串不可变。

其中:

1、unicode_length

2、PyUnicode_Concat

多个字符串相加效率低于join,join只分配一次内存;

1、unicode_repeat

效率要高于同个字符串相加;

1、unicode_getitem:暂时没有找到相应Python语句;

2、PyUnicode_Contains

5.3.3. 关联操作

其中:

1、unicode_subscript

test[1]会走unicode_subscript方法的index分支,test[0:5]会走slice分支;

5.3.4. to string

5.3.5. hash

5.3.6. 比较

5.3.7. 内置方法

5.4 参考

Python源码剖析

本文作者:whj0709

阅读原文

本文为云栖社区原创内容,未经允许不得转载。

相关文章

网友评论

    本文标题:5. Python3源码—字符串(str)对象

    本文链接:https://www.haomeiwen.com/subject/vxcheftx.html