Python 源码初探
python中一切皆对象,而对象机制的基石便是PyObject
typedef struct _object {
int ob_refcnt;
struct _typeobject *ob_type;
}PyObject;
ob_refcnt便是引用计数,ob_type便是类型信息。那么其他对象都可以在此基础上扩展,添加自身的信息,比如
typedef struct _object {
int ob_refcnt;
struct _typeobject *ob_type;
long ob_ival;
}PyIntObject;
当时阅读到这里,最疑惑的是python中的类型对象和实例对象都是怎么实现?stuct PyTypeObject的一个实例PyType_Type便是类型对象的基础,所有类型对象的ob_type都是指向PyType_Type,包括PyType_type本身,也就是说下面的表达式是成立的:
PyType_Type->ob_type == &PyType_Type
一切很简单,比如
a = 1
a是一个int类型,a便是struct PyIntObject数据,int便是PyInt_Type(PyInt_type并不是一个struct,也是一个struct PyTypeObject数据)。这便是python中“一切皆对象”的完美实现。
另外,还有几点说明,需要警惕下:
- 在python的各种对象中,类型对象时超越引用计数的。类型对象“跳出三界外,不在五行中”,永远不会被析构。每个对象中指向类型对象的指针不会被视为类型对象的引用,就是说每个对象建立初始化化,并不会对类型对象的引用计数加一;销毁时并不会减一。估计类型对象的引用计数永远是1了。
- 在python中,PyIntObject和PyStringObject都引用了内存对象池,因为对于这些用经常频繁用到的数据,会有大量的时间浪费是内存的申请和销毁上(如果不适用内存对象池的话)。PyIntObject不仅使用了小整数对象池(范围从NSMALLNEGINTS到NSAMLLPOSINTS),还有专门的PyIntBlock来用于申请大整数对象。因此对于一个整数,在NSAMLLNEGINTS和NSMALLPOSINTS之间,如果数值相等,其id便是相等,但是其他的id就不同了。PyStringObject也有字符串内存池,对于size为0或者1的字符串,都会经过intern机制缓存起来,其id肯定相同,但是大于1的就不一定了,这个或许跟创建PyStrngObject采用的方法有关吧,有可能是PySting_FromString,PyString_InternInPlace,也有可能是PyString_InternFromString。
- 关于PyStringObject的一个效率问题。对于N个字符串的连接,如果采用直接相加的话,调用string_concat,就会有N-1的内存申请以及内存搬运工作。但是如果采用"".join([a, b, ..]的话,调用string_join,在开始时会一次性计算好内存,然后申请内存,将字符串拼接,生成PyStringObject即可。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。