设为首页 收藏本站
查看: 701|回复: 0

[经验分享] Python源码剖析(1)

[复制链接]

尚未签到

发表于 2017-4-24 08:26:31 | 显示全部楼层 |阅读模式
 

接触python有段时间了,说实话,当我第一次用的时候就喜欢上了这门语言,那种编程的流畅感真的让人耳目一新。但这将近一年来,我只是用python小打小闹的写个小游戏,分析个数据,还参加了一次数学建模比赛,并没有系统的了解它。最近突然想要深入学习这门语言,所以找了一些资料,意外发现了一本陈儒先生写的《python源码分析》,就干脆跟着这本书从源码开始,认真了解这门语言。同时,通过博客和大家分享一下我的学习经历
 
一 认识源码

俗话说,“巧妇难为无米之炊”,要分析源码首先要得到源码。当然,python的源码很容易获得,这里给出官网的下载地址:
       https://www.python.org/ftp/python/2.7.6/Python-2.7.6.tgz

       虽然书中分析的是几年前的2.5版本的python,但是本着与时俱进的原则,我们还是用最新版本的2.7.6的源码。
解压缩后的目录结构如下:

DSC0000.png


介绍几个主要模块:
Include:python用到的所有的头文件,如果你想过用C/C++模块拓展python,就可以用到这里的头文件
Lib:这里包含了所有用python语言编写的内部标准库
Modules:包含了所有用C语言编写的模块,主要是一些对速度要求比较高的模块,如readline、tkinter等
Parser:包含了python的解释器中scanner和parser等部分,用来对python代码进行句法分析,此外还有一些很给力的小工具,能自动生成python词语法分析器
Objects:包含了所有python的内建对象,包括整数、list、dict等
Python:包含了python解释器的Compiler和执行引擎部分,从名字也看得出,是python的核心所在
Tools:一看就知道,这是各种工具的集合
Pcbuild:Visual Studio的工程文件,分析源码时很有用
 
二 python内建对象

     了解python的人都知道,python中所有的东西都被当作对象处理,变量、函数甚至数据类型都无一例外,python中大量的内建对象也无疑是python核心的重要组成部分,也正是python设计哲学的体现,因此,我们就从内建对象开始,一步步征服python源代码。
首先,我们打开刚才的Include文件夹,找到object.h 头文件,看看python中的对象是如何定义的。
Python中,所有的东西都是对象,而所有的对象都拥有相同的内容,这些都定义在PyObject结构体中,可以说是python对象机制的核心:
 

[object.h]
Typedef struct_object{
PyObject_HEAD
}PyObject;
事实上,python对象所有的秘密都藏在这个叫PyObject__HEAD的宏中:
 

[object.h]
#ifdef Py_TRACE_REFS
/* Define pointers to support a doubly-linked list of all live heap objects. */
#define _PyObject_HEAD_EXTRA            \
struct _object *_ob_next;           \
struct _object *_ob_prev;
#define _PyObject_EXTRA_INIT 0, 0,
#else
#define _PyObject_HEAD_EXTRA
#define _PyObject_EXTRA_INIT
#endif
/* PyObject_HEAD defines the initial segment of every PyObject. */
#define PyObject_HEAD                   \
_PyObject_HEAD_EXTRA                \
Py_ssize_t ob_refcnt;               \
struct _typeobject *ob_type;
这里涉及到了条件编译的概念,翻译一下:
 
1 如果定义了 Py_TRACE_REFS:
      /* 定义一个指针指向一个保存所有堆中存活的对象的双向链表 */
     _PyObject_HEAD_EXTRA   替换为两行代码 (其中 \ 符用来续行): 

struct _object  *_ob_next;
struct _object  *_ob_prev;
    定义 _PyObject_EXTRA_INIT 为   0,  0,
 
2 如果没定义Py_TRACE_REFS:
    _PyObject_HEAD_EXTRA 与 _PyObject_EXTRA_INIT都定义为空。(防止报错)
    /* PyObject_HEAD 定义了每个Pyobject的初始化部分 */
    PyObject_HEAD 替换为三行代码:

_PyObject_HEAD_EXTRA;
Py_ssize_t ob_refcnt;
struct _typeobject  *ob_type;
 
当我们在vs的release模式下编译时,不会定义Py_TRACE_REFS。 因此,最终的PyObject定义很简单:

[object.h]
Typedef struct_object{
Py_ssize_t ob_refcnt;               
struct _typeobject *ob_type;
}PyObject;
 
在这里,我们不妨用vs的追踪一下这里的Py_ssize_t,看看他到底是什么。用vs打开PcBuilt文件夹中的解决方案,打开pythoncore工程/外部依赖项/object.h,找到但蓝色字体标记的Py_ssize_t,按F12转到定义:

[pyport.h]
typedef ssize_t     Py_ssize_t;
 继续追踪:

[pyconfig.h]
typedef _W64 int ssize_t;
 
这里的_W64是为了兼容64位系统,可以忽略,所以Py_ssize_t本质就是int。因此,最终的PyObject的定义为:

[object.h]
Typedef struct_object{
int ob_refcnt;           
struct _typeobject *ob_type;
}PyObject;
 
2 变量的作用
 
下面,我们分析一下PyObject中的两个参数:
    1 ob_refcnt: 实质是int整数,用来实现垃圾管理机制,代表对象的引用次数,当它为零时,说明没有任何 变量名引用这个对象了,因而对象会被处理掉,腾出内存
    2 ob_type:类型对象,用来指向表示对象类型。怎么,不懂?别急,留个伏笔,后面我会详细讲。
所以python 中对象机制的核心很简单:一个引用计数,一个类型信息。
 
3 其他的部分
 
作为python对象机制的基础,pyobject定义了所有对象都必须有的部分,它占据了每个对象内存空间的最前端。最前端,意思就是除了Pyobject外,每个对象还应该占有更多的内存空间,还应该有自己“其他的部分”了?这是肯定的,因为要是所有的对象都只包含这两个东西,那么岂不是只有一种对象了,这太不现实了。
那么,这“其他的部分”又有什么呢?

[intobject.h]
typedef struct{
Pyobject_HEAD
long ob_ival;
}PyVarObject;
       
       这是python中的整数对象的定义,它里面除了Pyobject_HEAD外,还有一个long型的变量ob_ival,不用说你大概也猜到了,这是整数的数值。同理,字符串对象,list和dict对象,还有其他成千上万的对象,都是这种模式,即Pyobject_HEAD + 自己的“其他的部分”。
 
4 变长与定长对象
 
       我们知道,int在python只是一个整型变量,他的“其他东西”就是一个int型数值ob_ival,他占的内存大小是固定的,因此被称为“定长对象”。当然,与之对应的,python中同样会有“变长对象”,即他们的内存长度会随着情况不同而改变,举个很简单的例子:字符串。与int类似,python中的字符串的“其他的部分”显然应该是“一个字符串”。当然,我们都知道,C语言中没有“一个字符串”的概念的,只有“N个char型变量的数组”。但是,即使是这样,这N也是个不确定因素,“python”与“java”占内存大小不会是一样的,与之类似的明显还有包含“N个Object对象”的list、“N个Key—Value”的dict,这些,就是“变长对象”。
那这个变长对象python又是怎么描述的呢?接着往下看:

[object.h]
#define PyObject_VAR_HEAD       \
PyObject_HEAD           \
Py_ssize_t ob_size; /* Number of items in variable part */

typedef struct {
PyObject_VAR_HEAD
} PyVarObject;
 
原来,在PyObject对象之外,还有一个表示对象的结构体——PyVarObject。
      我们看到,PyVarObject中多了一个ob_size变量,它的作用就是用来表示上面的N,用来改变对象的长度。有一点要注意的,那就是ob_size 代表的是对象中的元素个数,而不是对象占的字节数,比如“abc”的N为4(别忘了结束符\0),[1,2,3,4,5]的N为5。
而从PyVarObject的定义看出,他只是一个PyObject的拓展,其开始部分与PyObject相同,都是Pyobject_HEAD,因此,python中的对象引用非常统一,使用一个PyObject*类型的指针就可以调用任意一个对象。
       据此,我们有理由推测,python中变量不用声明类型,拿来即用的强大功能,正是源自于此。
5 类型对象
目前,我们知道,通过PyVarObject的ob_size变量,可以改变变长对象的内存长度。然而,我们还并没有看到python具体是怎么做到这点的。还记不记得,在前面讲PyObject_HEAD的定义时,我埋了一个伏笔,那就是_typeobject *ob_type,那个表示对象类型的指针。
现在,我们转到 _typeobject的定义:

typedef struct _typeobject {
PyObject_VAR_HEAD
const char *tp_name; /* For printing, in format "<module>.<name>" */
Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */
/* Methods to implement standard operations */
destructor tp_dealloc;
printfunc tp_print;
...
/* More standard operations (here for binary compatibility) */
hashfunc tp_hash;
ternaryfunc tp_call;
...
} PyTypeObject;
 
承认信息量有点大,简单梳理一下,主要有四条信息:
       1 类型名,tp_name,格式为<module>.<name>,用于内部调用和方便调试
       2 创建对象时分配内存空间大小的变量, tp_basicsize和tp_itemsize,分别代表基本的大小和里面元素的 大小
       3 与对象相关的操作,如tp_print这样的函数
       4 要描述的本类型的其他信息
不知道你们有没有发现,这里的PyTypeObject结构体,实际上实现了面向对象编程里“类”的概念,不仅是因为它包含变量属性和方法,背后还有很多学问,再此同样埋个伏笔,后面会结合python的类型与对象体系详细分析。
好了,今天先写这些,下篇继续。
 
 
 

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-368384-1-1.html 上篇帖子: Python Paste笔记 下篇帖子: Python date测试
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表