python底层实现原理,python是非底层编程语言

  python底层实现原理,python是非底层编程语言

  本文主要介绍底层Python对象的源代码学习。有需要的朋友可以借鉴一下,希望能有所帮助。祝大家进步很大,早日升职加薪。

  

目录
1.PyObject:对象2的基础。PyVarObject:变长对象2.1浮点对象2.2列表对象3的基础。pytype object:type 4的基础。PyType_Type:类型5的类型。pybase object _ Type:Type 6的基础。在《Python源码学习笔记:P YTON》中补充,我们对Python的对象类型体系有了一定的了解。这篇博客将从源代码层面介绍Python中的everything is an object的底层实现。

  

1. PyObject:对象的基石

  在Python解释器的c层,所有对象都是基于PyObject的。

  c源代码如下:

  typedef struct _object {

  _ PyObject _ HEAD _ EXTRA

  Py _ ssize _ t ob _ refcnt

  PyTypeObject * ob _ type

  } PyObject

  源代码的解释:

  _PyObject_HEAD_EXTRA:主要用于实现双向链表(分析源代码时暂时忽略)。

  Ob_refcnt:引用计数,用于垃圾收集机制。当这个参数减小到0时,意味着对象将被删除(Py_ssize_t可以作为int或者long使用,有兴趣可以看看它的定义)

  Ob_type:类型指针,指向对象的PyTypeObject(后面介绍),描述实例对象的数据和行为。例如,PyLongObject的ob_type指向PyLong_Type。

  

2. PyVarObject:变长对象的基础

  与PyObject相比,PyVarObject只有一个属性ob_size,表示边长对象中有多少个元素。

  c源代码如下:

  typedef结构{

  PyObject ob _ base

  Py _ ssize _ t ob _ size/*可变部分中的项目数*/

  } PyVarObject

  定长对象和变长对象的总体结构图如下:

  宏定义:对于一个特定的对象,根据其大小是否固定,需要包含头PyObject或PyVarObject。为此,头文件准备了两个宏定义,以方便其他对象的使用:

  # define py object _ HEAD py object ob _ base;

  # define py object _ VAR _ HEAD PyVarObject ob _ base;

  

2.1 浮点对象

  这里简单以浮点对象为定长对象的例子,介绍相关概念。稍后将详细分析浮动对象的源代码。

  对于固定大小的浮点对象,有必要基于PyObject头用双精度浮点数double来实现它们:

  typedef结构{

  PyObject _ HEAD

  double ob _ fval

  } PyFloatObject

  图示如下:

  

2.2 列表对象

  这里简单以list对象为变长对象的例子,介绍相关概念。后面会详细分析list对象的源代码。

  对于大小不固定的列表对象,需要用基于PyVarObject头的动态数组来实现。该数组存储列表中包含的对象的指针,即PyObject指针:

  typedef结构{

  PyObj

  ect_VAR_HEAD

   PyObject **ob_item;

   Py_ssize_t allocated;

  } PyListObject;

  

  源码解读:

  ob_item:指向动态数组的指针,数组中保存元素对象指针

  allocated:动态数组的总长度,即列表当前的容量

  ob_size:当前元素个数,即列表当前的长度(这里的长度是指:列表包含n个元素,则长度为n)

  图示如下:

  

  

  

3. PyTypeObject:类型的基石

  问题:不同类型的对象所需存储空间不同,创建对象时从哪得知存储信息呢?以及如何判断一个给定对象支持哪些操作呢?

  注意到,PyObject结构体中包含一个指针ob_type,指向的就是类型对象,其中就包含了上述问题所需要的信息

  C源码如下:(只列出了部分,后续会结合具体类型进行分析)

  

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

   getattrfunc tp_getattr;

   setattrfunc tp_setattr;

   // ...

   /* Attribute descriptor and subclassing stuff */

   PyObject *tp_bases;

   // ...

  } PyTypeObject;

  

  源码解读:

  PyObject_VAR_HEAD表示PyTypeObject是变长对象

  tp_name:类型名称

  tp_basicsize、tp_itemsize:创建实例对象时所需的内存信息

  tp_print、tp_getattr等:表示该类型支持的相关操作信息

  tp_bases:指向基类对象,表示类型的继承信息

  PyTypeObject就是类型对象在C层面的表示形式,对应面向对象中类的概念,其中保存着对象的元信息(即一类对象的操作、数据等)。

  下面以浮点类型为例,列出了PyFloatObject和PyTypeObject之间的关系结构图示:(其中两个浮点实例对象都是PyFloatObject结构体,浮点类型对象float是一个PyTypeObject结构体变量)

  

  由于浮点类型对象唯一,在C语言层面作为一个全局变量静态定义即可。C源码如下:(只列出了部分)

  

PyTypeObject PyFloat_Type = {

   PyVarObject_HEAD_INIT(&PyType_Type, 0)

   "float",

   sizeof(PyFloatObject),

   0,

   (destructor)float_dealloc, /* tp_dealloc */

   // ...

   (reprfunc)float_repr, /* tp_repr */

   // ...

  };

  

  源码解读:

  第二行PyVarObject_HEAD_INIT(&PyType_Type, 0):初始化了ob_refcnt、ob_type、ob_sie三个字段,其中ob_type指向了PyType_Type(稍后会继续介绍,它就是type),即:float的类型是type

  第三行"float":将tp_name字段初始化为类型名称float

  

  

4. PyType_Type:类型的类型

  通过PyFloat_Type的ob_type字段,我们找到了type所对应的C语言层面结构体变量:PyType_Type,C源码如下:(只列出了部分)

  

PyTypeObject PyType_Type = {

   PyVarObject_HEAD_INIT(&PyType_Type, 0)

   "type", /* tp_name */

   sizeof(PyHeapTypeObject), /* tp_basicsize */

   sizeof(PyMemberDef), /* tp_itemsize */

   (destructor)type_dealloc, /* tp_dealloc */

   // ...

   (reprfunc)type_repr, /* tp_repr */

   // ...

  };

  

  内建类型和自定义类对应的PyTypeObject对象都是通过这个PyType_Type创建的。在第二行PyVarObject_HEAD_INIT(&PyType_Type, 0)中,PyType_Type把自己的ob_type字段设置成了它自己,即type的类型是type

  把PyType_Type加入到结构图中,图示如下:

  

  

  

5. PyBaseObject_Type:类型之基

  object是另外一个特殊的类型,它是所有类型的基类。如果要找到object对应的结构体,我们可以通过PyFloat_Type的tp_base字段来寻找,因为它指向的就是float的基类object。但是我们查看源码发现,PyFloat_Type中并没有初始化tp_base字段:

  

  同样地,我们查看Objects文件夹下的各种不同类型所对应的结构体,发现tp_base字段均没有初始化,于是寻找将tp_base字段初始化的函数:

  

void

  _Py_ReadyTypes(void)

  {

   if (PyType_Ready(&PyBaseObject_Type) < 0)

   Py_FatalError("Cant initialize object type");

   if (PyType_Ready(&PyType_Type) < 0)

   Py_FatalError("Cant initialize type type");

   // ...

   if (PyType_Ready(&PyFloat_Type) < 0)

   Py_FatalError("Cant initialize float type");

   // ...

  }

  

  _Py_ReadyTypes中统一调用了PyType_Ready()函数,为各种类型设置tp_base字段:

  

int

  PyType_Ready(PyTypeObject *type)

  {

   // ...

   /* Initialize tp_base (defaults to BaseObject unless thats us) */

   base = type->tp_base;

   if (base == NULL && type != &PyBaseObject_Type) {

   base = type->tp_base = &PyBaseObject_Type;

   Py_INCREF(base);

   }

   // ...

  }

  

  可以看到,PyType_Ready在初始化tp_base字段时,对于PyBaseObject_Type,不会设置tp_base字段,即object是没有基类的,这就是为了保证继承链有一个终点。

  PyBaseObject_Type源码如下:(只列出了部分)

  

PyTypeObject PyBaseObject_Type = {

   PyVarObject_HEAD_INIT(&PyType_Type, 0)

   "object", /* tp_name */

   sizeof(PyObject), /* tp_basicsize */

   0, /* tp_itemsize */

   object_dealloc, /* tp_dealloc */

   // ...

   object_repr, /* tp_repr */

   // ...

   0, /* tp_base */

   // ...

  };

  

  源码解读:

  第二行PyVarObject_HEAD_INIT(&PyType_Type, 0):把ob_type设置为PyType_Type,即object的类型是type

  将PyBaseObject_Type加入到结构图中,图示如下:

  

  

  

6. 补充

  object的类型是type,type的基类是object。先有鸡还是先有蛋?

  答:

  前面我们提到,在各种类型对应的C语言结构体变量初始化的时候,tp_base字段都是没有设置具体值的,直到_Py_ReadyTypes()函数执行时,才通过PyType_Ready()去初始化各类型的tp_base。

  在PyBaseObject_Type初始化时,会将ob_tyep字段设置为PyType_Type,即object的类型为type;在_Py_ReadyTypes函数中,会通过PyType_Ready()设置PyType_Type的tp_base字段为PyBaseObject_Type。所以这里本质上不是一个先有鸡还是先有蛋的问题。

  PyTypeObject保存元信息:某种类型的实例对象所共有的信息保存在类型对象中,实例对象所特有的信息保存在实例对象中。以float为例:

  

  • 无论是3.14,还是2.71,作为float对象,它们都支持加法运算,因此加法处理函数的指针就会保存在类型对象中,即float中。
  • 而这两个float对象的具体值都是各自特有的,因此具体数值会通过一个double类型的字段保存在实例对象中。

  以上就是Python对象的底层实现源码学习的详细内容,更多关于Python对象底层的资料请关注盛行IT软件开发工作室其它相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: