Python 源码阅读 —— int
admin
2023-07-31 00:35:57
0
========================== 

代码我也仅仅是粗粗读了一遍, 可能出现疏漏和理解错误, 发现了望指出哈.

今天面了一家靠谱的创业公司, 可惜不是Python向的, 想继续玩Python是有代价的, 选择余地太窄了……

话说写文章很耗时间, 这个花了两个多小时….主要还是自个绘图渣效率低:(

准备找工作事宜很占时间, 后面只能慢慢来了(好像还很多很多的样子)


示例

1234567891011 >>> a = 1>>> b = 1>>> id(a) == id(b)True >>> c = 257>>> d = 257>>> id(c) == id(d)False #在python2.x中, 对于大的序列生成, 建议使用xrange(100000) 而不是range(100000), why?

源码位置 Include/intobject.h |
Objects/intobject.c


PyIntObject

1234 typedef struct {    PyObject_HEAD    long ob_ival;} PyIntObject;

结构

PyIntObject


几个构造方法

12345678910111213 # 从字符串, 生成PyIntObject对象PyAPI_FUNC(PyObject *) PyInt_FromString(char*, char**, int); # 从Py_UNICODE, 生成PyIntObject对象#ifdef Py_USING_UNICODEPyAPI_FUNC(PyObject *) PyInt_FromUnicode(Py_UNICODE*, Py_ssize_t, int);#endif # 从long值, 生成PyIntObject对象PyAPI_FUNC(PyObject *) PyInt_FromLong(long); PyAPI_FUNC(PyObject *) PyInt_FromSize_t(size_t);PyAPI_FUNC(PyObject *) PyInt_FromSsize_t(Py_ssize_t);

这几个方法, 只需要关注

12 # 因为大家最后都调用这个方法完成对象生成PyAPI_FUNC(PyObject *) PyInt_FromLong(long);


具体的构造方法 PyInt_FromLong

这个方法的定义

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152 PyObject *PyInt_FromLong(long ival){    register PyIntObject *v;     /* MARK: 如果, 值在小整数范围内, 直接从小整数对象池获取得到对象 */     #if NSMALLNEGINTS + NSMALLPOSINTS > 0    if (NSMALLNEGINTS  ival & ival  NSMALLPOSINTS) {         /* MARK: small_ints是什么后面说 */        v = small_ints[ival + NSMALLNEGINTS];        // 引用+1        Py_INCREF(v);         /* 这里先忽略, 计数 */        #ifdef COUNT_ALLOCS            if (ival >= 0)                quick_int_allocs++;            else                quick_neg_int_allocs++;        #endif         // 返回        return (PyObject *) v;    }    #endif     // 如果free_list还不存在, 或者满了    if (free_list == NULL) {        // 新建一块PyIntBlock, 并将空闲空间链表头部地址给free_list        if ((free_list = fill_free_list()) == NULL)            // 如果失败, 返回            return NULL;    }     // 从free_list分出一个位置存放新的整数     /* Inline PyObject_New */    // 使用单向链表头位置    v = free_list;     // free_list指向单向链表下一个位置    free_list = (PyIntObject *)Py_TYPE(v);     // 初始化对象, 类型为PyInt_type, 值为ival    PyObject_INIT(v, &PyInt_Type);    v->ob_ival = ival;     // 返回    return (PyObject *) v;}

注意这里的Py_TYPE()方法, 在我们第一篇文章里面有提到, 不知道的回去复习下对象的数据结构

1 #define Py_TYPE(ob)             (((PyObject*)(ob))->ob_type)

简而言之:

12345 1. 先判断数值是否是小整数, 是的话从小整数对象池里面直接返回(这个池固定大小, 下一点讲) 2. 如果不是, 从通用整数对象池里面取一个, 初始化返回(如果这时候通用整数对象池还不存在或者已经满了, 新建一个池加入维护. 通用整数对象池后面讲)


小整数对象池

先看定义

1234567891011121314151617 #ifndef NSMALLPOSINTS#define NSMALLPOSINTS           257#endif #ifndef NSMALLNEGINTS#define NSMALLNEGINTS           5#endif #if NSMALLNEGINTS + NSMALLPOSINTS > 0/* References to small integers are saved in this array   so that they can be shared.   The integers that are saved are those in the range   -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive).*/ static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];#endif

其实, 小整数对象池就是一个PyIntObject指针数组(注意是指针数组), 大小=257+5=262, 范围是[-5, 257) 注意左闭右开. 即这个数组包含了262个指向PyIntObject的指针.

结构

small_ints

创建整数时, 如果在[-5, 257)范围, 直接返回已经存在的整数对象指针, 所以我们看到开头的例子, id比较一个true/一个false

小整数对象池, 在一开始就初始化了, 其初始化代码

1234567891011121314151617181920 int_PyInt_Init(void){    PyIntObject *v;    int ival;     // 注意这里, free_list再次出现 #if NSMALLNEGINTS + NSMALLPOSINTS > 0     // 循环, 逐一生成    for (ival = NSMALLNEGINTS; ival ob_ival = ival;         // 放到数组里        small_ints[ival + NSMALLNEGINTS] = v;    }#endif     return 1;}

代码很眼熟吧, 觉得不眼熟回上面看代码

结论

123 1. 小整数对象池缓存 [5, 257) 内的整数对象, 数值在这个范围的整数对象有且只存在一个... 2. 小整数对象池, 只是一个指针数组, 其真正对象依赖通用整数对象池

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
python清除字符串里非数字... 本文实例讲述了python清除字符串里非数字字符的方法。分享给大家供大家参考。具体如下: impor...