Python中源码之字符串底层解析

本文深入解析Python2中的PyStringObject和Python3中的PyUnicodeObject。PyStringObject通过PyObject_VAR_HEAD的ob_size变量记录字符串长度,PyUnicodeObject使用不同的编码方式节省内存。字符串创建涉及intern机制,用于内存优化。Python2的字符串连接效率较低,推荐使用join方法提高性能。
摘要由CSDN通过智能技术生成


  Python的对象分为 “可变对象” 和 “不可变对象”, 可变对象也还可以分为 “可变” 和 “不可变”,这里所谓的可变就是说对象所维护的数据是可以变化的,举个例子说明,list容器中的元素可以进行添加、删除、修改等操作,也就是说这个容器对象所维护的数据是可以动态变化的;而所谓 “不可变” 就是说,此对象中所维护的数据一旦创建后就不能发生改变,即便对这个对象进行某种操作后生成的数据也只能是一个新的地址,例如tuple容器。这一节我们将研究Python中的字符串对象。

1、Python2中的PystringObject

  在本节我们也会先来解析一下Python2中对于字符串对象的实现,然后再简述一下在Python3中的字符串对象和Python2中有什么不同。实际Python中的字符串对象就是通过PyStringObject来实现的, 它是一个内存大小可变的一个对象(不是说不可变吗?怎么又可变了?什么鬼?)。之所以说它可变是因为在创建字符串对象的时候,我们是不能提前预知字符串的长度的,所以在PyStringObject对象中必须要有可以用来记录字符串长度的成员。举个例子,‘java’ 和 ‘Python’ 这两个字符串的长度显然是不一样的,因此这两个字符串所占用的内存空间也是不一样的。But talk is cheap, show me the code, 让我们来看看底层C语言的实现

// stringobject.h
typedef struct {
   
    PyObject_VAR_HEAD;  // 这是在PyObject中定义的宏
    long ob_shash;
    int ob_sstate;
    char ob_sval[1];
}PyStringObject;

可以非常清楚地看见,PyStringObject的头部实际上是一个PyObject_VAR_HEAD,这个头部中维护了一个ob_size的变量,这个变量用来保存可变内存的大小。

  ob_shash变量是用来缓存该对象的哈希值,之所以缓存哈希值是因为避免重复计算,它具体的实现算法大家有兴趣可以去参考一下源码,这里我们的重点是解析Python,就不展开了。

  ob_sstate变量用于记录该对象是否已经经过了intern机制的处理,这个intern机制是个啥?我们后面会详细聊这个牛逼哄哄的玩意儿。

  ob_sval是一个字符数组,这是个啥玩意儿?为啥数组长度只有1 ?你接着往下看就知道了。实际上这货是一个字符指针,这个指针指向了一段内存,而这段内存就是这个字符串对象中所维护的实际的字符串。这段装有实际字符串的字节数(在c语言中一个字符用一个字节来存储)就是由上面说的PyObject_VAR_HEAD中的ob_size变量来维护的。需要注意的是,ob_sval这个字符指针指向的内存字节数也就是长度并不是ob_size,而是ob_size+1。我们知道在C语言中,对于一段字符串结束的标志是一个叫做 ‘\0’ 的字符,所以在PyStringObject的字符串对象中,不以 ‘\0’ 作为结束处理,万一这个字符串中间有这个字符呢,那不就傻X了吗?所以我们在最后末尾添加结束字符,所以这段内存就必须满足ob_sval[ob_size + 1] = ‘\0’. 实际上在Python2中所有变长对象的实现机制都是基于这个叫做ob_size的玩意儿来的。

  • 1.2 PyStringObject的创建

  与Python中的整数对象一样,PyStringObject对象也有多种创建方式。原生的创建方式就是通过PyString_FromString

// stringobject.c
PyObject* PyString_FromString(const char *str) {
   
    register size_t size;
    register PyStringObject *op;
    // (1)判断字符串长度
    size = strlen(str);
    if (size > PY_SSIZE_T_MAX) {
   
        return null;
}
    // (2)处理null string
    if (size == 0 && (op = nullstring) != NULL) {
   
        return (PyObject *)op;
}
    // (3)处理字符
    if (size == 1 && (op = characters[*str & UCHAR_MAX]) != NULL) {
   
        return (PyObject *)op;
}
    // 创建新的PyStringObject对象
    op = (PyStringObject *)PyObject_MALLOC(sizeof(PyStringObject) + size
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值