Python源码之整数对象底层解析


  在本章中我会先讲述一下在Python2中整数对象的实现原理,然后在解析一下Python2和Python3在整数对象中的原理上的差异。

1、PyIntObject

  在Python中 “整数”这个概念的实现通过PyIntObject 对象来完成的,在Python的对象体系中分为两个大类,一类是 “可变对象”, 一类是 “不可变对象”。而整数对象就属于不可变的对象。所谓不可变对象是指,一旦这个对象被创建后,就不能够再改变它的值了。

  不管在哪种语言中,整数的应用是非常广泛,这也意味着它的创建和销毁也会非常频繁,我们知道Python中对对象的管理主要采用引用计数的机制,也就是说如此频繁的创建和销毁会消耗太多的系统性能,因为我们知道Python是有C实现的,C对堆内存的管理是通过两个函数接口实现的,malloc和free, 这个两个函数直接包装了操作系统的核心接口,即意味着系统将频繁地在用户态和核心态之间切换。那么Python是如何来处理整数对象的呢?先看看静态的整数对象在底层的定义------PyIntObject

// intobject.h
typedef struct {
   
	Pyobject_HEAD
	long ob_ival;
} PyIntObject;

  可以看见PyIntObject实际上就是对C整数类型long的的简单包装,通过对整数对象的源码可以知道,例如加法操作,加法操作执行后,确实没有改变参与操作的对象而是重新创建了一个新的PyIntObject对象,也就可以证明它确实是不可变的对象。

2、PyIntObject对象的创建和维护

  • 2.1 对象创建的三种途径

PyObject* PyInt_FromLong(long ival)
PyObject* PyInt_FromString(char* s, char** pend, int base)
#ifdef Py_USING_UNICODE
	PyObject* PyInt_FromUnicode(Py_UNICODES *s, int length, int base)
#endif

  可以看见分别是从long值,从字符串以及Py_UNICODES对象生成,我们这里只看通过long值生成的方式,因为其他两种方式本质上利用了一些设计模式的思想进行了接口转换。

为了能够更加清晰地理解PyIntObject的创建过程,我们需要先了解Python中对象在内存的组织方式,现在我们就通过源码看看Python中的整数对象系统的结构。

  • 2.2 小整数对象

    在编程中,我们可能经常用到比较小的整数,例如0、1、5等等,可以想象C语言中for循环。在Python中所有的对象都存在于系统堆内存中,上面我们也说这些对象的操作是会影响整体性能的。所以在Python中,对于小整数对象的处理引入了对象池的技术,由于整数对象是不可变的对象,也就意味着对象池里的每一个对象都能够被共享。实际上这个小整数对象池在C的源码中被定义为 PyIntObject* , 这个小整数集的范围在[-5, 257)之间,在源码中可以去修改这个数值,但是修改后你将重新编译Python。

    对于小整数对象,Python将这些对应的PyIntObject直接缓存在内存中。那么对于大整数的处理呢?

  • 2.3 大整数对象

  小整数对象完全缓存在对象池中,对于其他整数,Python运行环境将提供一块内存空间,这些内存空间由这些大整数轮流使用,换句话 说,谁需要就谁使用,这样避免了不断malloc申请堆内存带来的开销又那能够考虑效率。

  在Python中,有一个PyIntBlock的结构,在这个结构的基础上,实现了一个单向链表,先看看源码中的定义:

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值