bilibili视频讲解:https://space.bilibili.com/431392724
b站用户名:平凡的久月

1. PyBytesObject

变长对象(数据长度在定义时是不知道的,只能在创建时才能确定)

不可变对象(改变值内存地址会发生改变)

1.1 定义

// Include/bytesobject.h
#ifndef Py_LIMITED_API
typedef struct {PyObject_VAR_HEADPy_hash_t ob_shash;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.*/
} PyBytesObject;
#endif// python3 中不再使用 PyBytesObject 作为 String 类的底层实现
#define PyObject_VAR_HEAD  PyVarObject ob_base;typedef struct {PyObject ob_base;Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;typedef struct _object {_PyObject_HEAD_EXTRAPy_ssize_t ob_refcnt;struct _typeobject *ob_type;
} PyObject;// 等价于下列表达
typedef struct {Py_hash_t ob_shash;   // 缓存该对象的hash值,避免重新计算(初始值-1),dict中详细解释作用// PyBytesObject内部维护的字符串必须以'\0'结尾char ob_sval[1];      // 字符指针,指向ob_size+1个字节的内存'\0'Py_ssize_t ob_size;Py_ssize_t ob_refcnt;struct _typeobject *ob_type;
} PyBytesObject;
#endif
PyTypeObject PyBytes_Type = {PyVarObject_HEAD_INIT(&PyType_Type, 0)"bytes",PyBytesObject_SIZE,  // ob_sizesizeof(char),        // 一个字节bytes_dealloc,                      /* tp_dealloc */0,                                          /* tp_print */0,                                          /* tp_getattr */0,                                          /* tp_setattr */0,                                          /* tp_reserved */(reprfunc)bytes_repr,                       /* tp_repr */// 支持三种操作&bytes_as_number,                           /* tp_as_number */&bytes_as_sequence,                         /* tp_as_sequence */&bytes_as_mapping,                          /* tp_as_mapping */(hashfunc)bytes_hash,                       /* tp_hash */// ......0,                                          /* tp_init */0,                                          /* tp_alloc */bytes_new,                                  /* tp_new */PyObject_Del,                               /* tp_free */
};

1.2 创建PyBytesObject

Python提供了多种路径从C中原生的字符串创建PyBytesObject对象

  • PyBytes_FromString

    PyObject *
    PyBytes_FromString(const char *str)
    {size_t size;PyBytesObject *op;assert(str != NULL);size = strlen(str);// 判断字符串长度是否超过系统寻址能力if (size > PY_SSIZE_T_MAX - PyBytesObject_SIZE) {PyErr_SetString(PyExc_OverflowError,"byte string is too long");return NULL;}// 处理空串:通过nullstring,始终只有一个if (size == 0 && (op = nullstring) != NULL) {#ifdef COUNT_ALLOCSnull_strings++;
    #endifPy_INCREF(op);return (PyObject *)op;}// 处理单个字符(字符串对象缓冲池)if (size == 1 && (op = characters[*str & UCHAR_MAX]) != NULL) {#ifdef COUNT_ALLOCSone_strings++;
    #endifPy_INCREF(op);return (PyObject *)op;}// 创建新的PyBytesObject对象,并初始化/* Inline PyObject_NewVar */op = (PyBytesObject *)PyObject_MALLOC(PyBytesObject_SIZE + size);if (op == NULL)return PyErr_NoMemory();(void)PyObject_INIT_VAR(op, &PyBytes_Type, size);op->ob_shash = -1;memcpy(op->ob_sval, str, size+1);/* share short strings */if (size == 0) {nullstring = op;Py_INCREF(op);} else if (size == 1) {characters[*str & UCHAR_MAX] = op;Py_INCREF(op);}return (PyObject *) op;
    }
    

python3中没有ob_sstate这个变量!!!

  • PyBytes_FromStringAndSize

    PyObject *
    PyBytes_FromStringAndSize(const char *str, Py_ssize_t size)
    {PyBytesObject *op;if (size < 0) {PyErr_SetString(PyExc_SystemError,"Negative size passed to PyBytes_FromStringAndSize");return NULL;}// 单个字符if (size == 1 && str != NULL &&(op = characters[*str & UCHAR_MAX]) != NULL){#ifdef COUNT_ALLOCSone_strings++;
    #endifPy_INCREF(op);return (PyObject *)op;}// 创建新的PyBytesObject对象,并初始化op = (PyBytesObject *)_PyBytes_FromSize(size, 0);if (op == NULL)return NULL;if (str == NULL)return (PyObject *) op;memcpy(op->ob_sval, str, size);/* share short strings */if (size == 1) {characters[*str & UCHAR_MAX] = op;Py_INCREF(op);}return (PyObject *) op;
    }
    

1.3 intern机制

1.3.1 Python2中

Python2中通过PyString_InternInPlace实现intern机制

检查两项内容:

(1)是否是PyBytesObject?

(2)是否被intern机制处理过(保证只处理一次)

void
PyString_InternInPlace(PyObject **p)
{register PyStringObject *s = (PyStringObject *)(*p);PyObject *t;if (s == NULL || !PyString_Check(s))Py_FatalError("PyString_InternInPlace: strings only please!");/* If it's a string subclass, we don't really know what puttingit in the interned dict might do. */if (!PyString_CheckExact(s))return;if (PyString_CHECK_INTERNED(s))return;if (interned == NULL) {interned = PyDict_New();if (interned == NULL) {PyErr_Clear(); /* Don't leave an exception */return;}}t = PyDict_GetItem(interned, (PyObject *)s);if (t) {Py_INCREF(t);Py_SETREF(*p, t);return;}if (PyDict_SetItem(interned, (PyObject *)s, (PyObject *)s) < 0) {PyErr_Clear();return;}/* The two references in interned are not counted by refcnt.The string deallocator will take care of this */Py_REFCNT(s) -= 2;PyString_CHECK_INTERNED(s) = SSTATE_INTERNED_MORTAL;
}
  • intern是什么?PyDictObject对象–interned

  • 创建临时变量a,在intern中寻找是否有一样的对象。

  • intern中的指针不作为a的有效引用(不然a永远无法销毁)

细节问题:

(1)为什么创建的时候interned的键与值都设置为对象的PyObject指针?

(2)为什么将对象的引用计数减2?

1.3.2 Python3中

Python3中做了修改,移动到了sys库,编译器默认执行

from six.moves import intern
from sys import intern
str = "shanghai"
print(intern(str).__doc__)
// Modules/pyexpat.c
static PyObject*
string_intern(xmlparseobject *self, const char* str)
{PyObject *result = conv_string_to_unicode(str);PyObject *value;/* result can be NULL if the unicode conversion failed. */if (!result)return result;if (!self->intern)return result;value = PyDict_GetItem(self->intern, result);if (!value) {if (PyDict_SetItem(self->intern, result, result) == 0)return result;elsereturn NULL;}Py_INCREF(value);Py_DECREF(result);return value;
}

1.4 字符串缓冲池

一个字节的字符对应的对象缓冲池

static PyBytesObject *characters[UCHAR_MAX + 1];
static PyBytesObject *nullstring;

实现过程

(1)创建PyBytesObject对象

(2)进行intern操作

(3)缓存进缓冲池

1.5 与效率相关的问题

背景:实现100个字符串的拼接

实现方法:+

问题:创建N-1个对象,进行N-1次内存的申请与释放

根本原因:不可变对象

解决方法:对存储在list的一组对象进行连接操作(join)

一次申请N个对象使用的内存,并统计这些对象维护的字符串有多长,然后申请内存,最后拷贝到内存空间。

a = 345
b = a
c = 456
d = 456
print(a is b)
print(a is c)
print(c is d)e = "abc"
f = "abc"
g = "abd"
print(e is f)
print(e is g)# True
# False
# True
# True
# False

Python源码剖析(四)字符串对象相关推荐

  1. Python源码剖析[19] —— 执行引擎之一般表达式(2)

    Python源码剖析 --Python执行引擎之一般表达式(2) 本文作者: Robert Chen(search.pythoner@gmail.com ) 3.2     Simple.py 前面我 ...

  2. Python源码剖析2-字符串对象PyStringObject

    二. 1.PyStringObject与 PyString_Type PyStringObject是变长对象中的不可变对象.当创建了一个PyStringObject对象之后,该对象内部维护的字符串就不 ...

  3. python源码剖析—— python中的列表对象

    1. PyListObject对象 PyListObject 对象可以有效地支持插入,添加,删除等操作,在 Python 的列表中,无一例外地存放的都是 PyObject 的指针.所以实际上,你可以这 ...

  4. python源码剖析—— python中的字节码对象初探

    一.代码对象 每个初学python的人都会认为python是一种解释型语言,这个不能说错.但是python并不是真的对执行的python代码的每一行进行解释,虽然我们有一个所谓的"解释器&q ...

  5. python源码剖析笔记1——Python对象初见

    本文简书地址:http://www.jianshu.com/p/763f6cec7a9b 工作整两年了,用python最多,然而对于python内部机制不一定都清楚,每天沉醉于增删改查的简单逻辑编写, ...

  6. 《Python源码剖析》读书笔记

    <Python源码剖析>电子书下载 http://download.csdn.net/detail/xiarendeniao/5130403 Python源码在官网有下载链接,用ctags ...

  7. Python源码剖析[16] —— Pyc文件解析

    Python源码剖析[16] -- Pyc文件解析 2008-02-28 18:29:55|  分类: Python |举报 |字号 订阅 Python源码剖析 --Pyc文件解析 本文作者: Rob ...

  8. Python源码剖析[1] —— 编译Python

    [ 绝对原创,转载请注明出处] 注意 :第一部分Python总体架构采用了网络文档<The Architecture of Python>,这是网络上唯一可见的以剖析Python实现为己任 ...

  9. Python猫荐书系统之四:《Python源码剖析》

    大家好,新一期的荐书栏目如期跟大家见面了. 先来看看今天的主角是谁:<Python源码剖析--深度探索动态语言核心技术>,2008年出版,作者 @陈儒 ,评分8.7分. 是的,你没看错,出 ...

  10. Python源码剖析:前言

    第0章:前言 0.0 我的前言  在几个月学习的中,已经学习了python基本.进阶的语法,如果有读者不清楚的话,可以参考我之前的专栏<python进阶>.  而在这个专栏<pyth ...

最新文章

  1. html 类型转换,JavaScript怎么进行类型转换?
  2. python环境变量配置_Python的安装、认识、配置环境变量以及helloworld打印的两种方式
  3. 华为新系统鸿蒙能互通吗,「连接」万物的鸿蒙,能拯救华为手机吗?
  4. 选择嵌套_如何优雅地在JavaScript中访问嵌套对象
  5. 安卓手机刷软路由_华为路由AX3 Pro上手测评:用过最方便的路由器,没有之一...
  6. 数据分析之numpy
  7. dynamic programming 学习
  8. Git学习文档之一 学习文档-合并分支
  9. matlab波形反白,基于MATLAB的海岸污染物浓度扩散实验分析
  10. emc测试e3软件系数导入,EMC测试标准
  11. c语言求婚代码大全,求一个C语言表白的代码
  12. 为什么MASKRCNN中使用ROIAlign替代ROIPool
  13. DOS定时关机命令 windowXp
  14. 【数据压缩】使用Audacity软件分析浊音、清音爆破音的时域及频域特性。
  15. webpack4打包js
  16. jquery 封装幻灯插件_21个jQuery幻灯片插件
  17. win7关机一直卡在正在关机
  18. win10照片查看器_非常好用的19个Win10小技巧,学会之后事半功倍
  19. Ispell in Emacs
  20. Netty 数据传输载体 —— ByteBuf

热门文章

  1. 电路设计中的防爆设计原理与注意事项分析
  2. 写给非网工的CCNA教程(2)第一个协议--ARP协议
  3. 04 - 雷达的工作频率
  4. 高性能mysql第一章——架构
  5. Linux驱动加载总结
  6. ztek usb转串口 linux,Z-tek驱动下载_Z-tek usb转串口驱动官方下载 - 系统之家
  7. 高德地图提示com.autonavi.amap.mapcore.MapCore.nativeNewInstance问题
  8. 【lizhi125】比Nero更好用的免费小巧的光盘刻录软件——ImgBurn(中文版)
  9. VS2013过期激活,VS2013激活,vs2013序列号,VS2013密钥,VS013产品密匙
  10. 抖音计算机音乐的id,抖音卡点音乐叫什么名字 抖音卡点bgm介绍