Python源码学习(一)
python基础
Python中一切都是对象,一个实例是一个对象,生成实例的类也是对象,描述类的元类也是对象。
TODO:类的继承链的图片
这张图里面,可以看出来,无论是内置类型int还是自定义类型dog,他们的基类都是object。而且描述他们类型的元类型都是type,object是所有类型的基类,本质上也是一个类,所以他的类型也是type。Type是所有类型的类型,本质上也是一种类型,所以它继承自object,类型是它自己。总体来看,所有类型的基类都收敛于object,所有类型的类型都是type。
PyObject
Python中的变量只是一个跟对象关联的名字,保存的其实是指向实际对象的指针,变量的赋值操作也就是一个拷贝指针的操作。
Python中对象可以分为可变对象和不可变对象;顾名思义,区别就是创建后对象的值能不能修改。也可分为定长对象和变长对象:区别就是对象大小能不能改变
typedef struct _object {_PyObject_HEAD_EXTRAPy_ssie_t ob_refcnt; //引用计数PyTypeObject *ob_type; //类型指针
} PyObject;
PyObject结构体是所有对象共用的部分,这其中包含一个引用计数,记录被引用次数,一个类型指针,指向对象的类型对象,比如刚才的dog实例的类型对象,就是dog类。这是一个最基础的对象结构。
PyVarObject
下面这个是变长对象,跟PyObject相比,多出一个ob_size字段,用来记录元素个数。变长比如string,list。
typedef struct {PyObject ob_base;Py_ssize_t ob_size;
} PyVarObject;
PyTypeObject
typedef struct _typeobject {PyObject_VAR_HEADconst char *tp_name; //类型名称Py_ssize_t tp_basicsize, tp_itemsize; //创建对象所需的内存信息// 该类型支持的操作信息destructor tp_dealloc;printfunc tp_print;getattrfunc tp_getattr;setattrfunc tp_setattr;//...struct _typeobject *tp_base; //类型的继承信息//...
} PyTypeObject;
在创建对象的时候,不同的对象它肯定需要不同的内存大小,PyObject只提供了所有对象共有的信息,其他的一些元信息,都放在PyTypeObject这个结构体中,也就是前面说的类型对象,它来描述这个对象是什么类型,有什么继承关系,支持什么操作,需要多少内存这些信息。
Object 和 Type_Type
刚才我们还介绍了两个概念,一个是所有类的基类Object,还有一个是描述类型的类型,被称为元类型type。
PyTypeObject PyType_Type = {PyVarObject_HEAD_INIT(&PyType_Type, 0)"type",sizeof(PyHeapTypeObject),sizeof(PyMemberDef),(destructor)type_dealloc,//...(reprfunc)type_repr,(ternaryfunc)type_call,//...
};
PyTypeObject PyBaseObject_Type = {PyVarObject_HEAD_INIT(&PyType_Type, 0)"object",sizeof(PyObject),0,object_dealloc,//...object_repr,
};
Object背后的实体就是PyBaseObject_type,跟前面的类型对象对比,他没有设置tp_base字段记录继承信息,因为它要作为继承链的终点,防止进入死循环。
小结
到这里我们基本可以弄清楚python对象体系的关系。变量名指向一个实例对象,这个对象包含基本的pyobject,ob_type指向它的类型对象PyFloat_Object,这个类型对象的type字段中,指向的是类型的类型PyType_type对象,tp_base中记录着继承信息,基类是pyBaseObject_type,另外PyBaseObject_type是元类型的基类,PyType_Tpye是object的类型。
生命周期
接下来我们再了解一下对象的生命周期。
static PyObject *
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
{PyObject *obj;//...obj = type->tp_new(type, args, kwds);obj = _Py_CheckFunctionResult((PyObject*)type, obj, NULL);if (obj == NULL)return NULL;//...type = Py_TYPE(obj);if (type->tp_init != NULL) {int res = type->tp_init(obj, args, kwds);if (res < 0){assert(PyErr_Occurred());Py_DECREF(obj);obj = NULL;}else {assert(!PyErr_Occurred());}}return obj;
}
我们还记得类型对象中的tp_call字段,当对象被创建的时候会通过类型对象调用tp_call方法,这里先调用了tp_new申请内存,然后如果它有init的话会调用tp_init对对象进行初始化。这是两个比较关键的操作。
#define PyINCREF(op) (_Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA((PyObject*)(op))->ob_refcnt++)#define Py_DECREF(op)do{if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA--((PyObject*)(op))->ob_refcnt != 0)_Py_CHECK_PRECNT(op)else_Py_Dealloc((PyObject *)(op));} while (0)
对象的销毁是通过PyObject对象中的引用计数来判断的。刚才对象创建调用完tp_new方法之后,会执行增加引用计数的宏,然后init失败之后减少引用计数。这两个宏分别是Py_INCREF和Py_DECREF,可以看到都在操作pyObject中的记录引用次数的这个字段,在指针为零时还会会销毁或者回收对象。
不同的对象肯定有不一样的行为,通过行为可以把对象分成不同的类别。数值型的对象会有加减乘除等操作,序列型的对象有下标操作,关联型对象会产生约束。Python为每一个类别都定义了一个标准操作集。数值型对象比如int,float;序列型对象str,bytes,tuple,list;关联型对象dict
在类型对象PyTypeObject中,可以看到三个操作集的定义:type_as_number,type_as_sequence,type_as_mapping
typedef struct _typeobject
{PyObject_VAR_HEADconst char *tp_name;Py_ssize_t tp_basicsize, tp_itemsize;//...PyNumberMethods *tp_as_number; //数值型操作PySequenceMethods *tp_as_sequence; //序列型操作PyMappingMethods *tp_as_mapping; //关联型操作//...PyBufferProcs *tp_as_buffer;//...
} PyTypeObject;
static PyNumberMethods float_as_number = {float_add,float_sub,float_mul,float_rem,float_divmod,float_pow,//...
};
PyTypeObject PyFloat_Type = {PyVarObject_HEAD_INIT(&PyType_Type, 0)"float",sizeof(PyFloatObject),&float_as_number, // tp_as_number0, // tp_as_sequence0, // tp_as_mapping
};
只要类型对象提供相关的操作集,实例对象就会有这些行为。以float为例可以看到:
在PyFloat_Tpye类型对象中,定义了数值型操作集,序列型和关联型都是空的,所以只支持数值型操作,float_as_number中也详细对应了float版本的函数,有加减乘取余,取模等等。
Python源码学习(一)相关推荐
- python源码学习_【Python学习】Python源码阅读(一)
最近想读读Python源码,任何东西学习方法基本都是一样的,先从总体框架进行了解,再从自己侧重的方面逐步深入. 1. Python总体架构 左边是Python提供的大量的模块.库以及用户自定义的模块. ...
- Python源码学习笔记:Python程序执行过程与字节码
Python程序执行过程与字节码 注:本篇是根据教程学习记录的笔记,部分内容与教程是相同的,因为转载需要填链接,但是没有,所以填的原创,如果侵权会直接删除. 问题: 我们每天都要编写一些Python程 ...
- Python源码学习:多线程实现机制
Python源码分析 本文环境python2.5系列 参考书籍<<Python源码剖析>> 本文分析Python中的多线程机制,主要通过一个多线程的脚本来分析多线程的基本操作与 ...
- Python源码学习:Python类机制分析-用户自定义类
Python源码分析 本文环境python2.5系列 参考书籍<<Python源码剖析>> 上一文,分析了Python在启动初始化时,对内置类的一个基本的初始化流程,本文就简析 ...
- Python源码学习:Python类机制分析
Python源码分析 本文环境python2.5系列 参考书籍<<Python源码剖析>> 本文主要分析Python中类时如何实现的,在Python中,一切都是对象:任何对象都 ...
- Python源码学习:Python函数浅析-函数闭包
Python源码分析 本文环境python2.5系列 参考书籍<<Python源码剖析>> 上一篇分析了函数参数的分析后,本文分析函数闭包的实现.函数闭包即函数定义和函数表达式 ...
- Python源码学习:Python函数浅析-有参函数
Python源码分析 本文环境python2.5系列 参考书籍<<Python源码剖析>> 继续上一篇无参函数的调用后,本文将分析Python中的有参函数的大致流程,在Pyth ...
- Python源码学习:Python函数浅析-无参函数
Python源码分析 本文环境python2.5系列 参考书籍<<Python源码剖析>> 本文会大致分析一下Python中的函数机制.在Python中,函数是一个比较重要的类 ...
- Python源码学习:内建类型简析并简析int对象
Python源码分析 本文环境python2.5系列 参考书籍<<Python源码剖析>> 上一篇文章中已经大致分析了下,Python的启动执行流程,现在我们分析一下Pytho ...
- Python源码学习:启动流程简析
Python源码分析 本文环境python2.5系列 参考书籍<<Python源码剖析>> Python简介: python主要是动态语言,虽然Python语言也有编译,生成中 ...
最新文章
- 计算机专业PhD申请文书范文,美国留学博士申请文书怎么写之范文分享
- Linux Tomcat安装,Linux配置Tomcat,Linux Tomcat修改内存,Linux tomcat修改端口
- K3ERP连接数据库问题
- 深入理解ReactRedux
- 【Linux 内核】进程管理 ( 进程相关系统调用源码分析 | fork() 源码 | vfork() 源码 | clone() 源码 | _do_fork() 源码 | do_fork() 源码 )
- DOS调用21H存取中断向量
- 题解报告:hdu 4907 Task schedule
- php excel中解析显示html代码_骑士cms从任意文件包含到远程代码执行漏洞分析
- text-align:justify 使用参考
- oracle语法官方文档,Oracle官方文档必备语法知识
- 运行android程序时显示stop,Android系统.应用程序关闭时WorkManager是否正在运行?
- 生成指定大小的空文件
- python list 底层_深入Python列表的内部实现
- 微软开源 TensorFlow-DirectML,为 WSL2 提供 GPU 支持
- wdcp安装多种php版本共存
- HTML页面跳转及传递参数
- 弘玑Cyclone上榜36氪中国超自动化先锋企业
- JAVA 实现《黄金矿工》游戏
- android aidl oneway用法
- 通过three.js实现3d模型展示