Python构件:PyObject
Python构件:PyObject。深入使用Python语言之前,我们有必要熟悉其中的主要概念。十分简单,每个元素都是一个对象。这是我们学习Python内部原理的第一步,以便我们继续深入学习。
本文主要探讨的是如何在低版本Python系统中操作它的对象。接下来要讨论的CPython操作基于Python2.7.8。
在这里,我假定你们已经下载好了Python源码并已将其解压,如此,相关的源代码将能在系统跟文件夹下找到。
PyObject&PyVarObject
Python中的所有元素都是对象。从字面意思理解,你在Python中操作的任何元素都是一个由C语言实现的PyObject对象。
函数
切片
文件
类
迭代器
描述符
sequence对象
数值类型
值得一提的是,当你使用C语言结构原型时,Python对象在内部由PyObject和PyVarObject表示,其中PyVarObject是一种泛型对象。后者适用于各种可变尺寸的容器对象(动态的),而前者适用于其他对象(静态的)。
只要每个内建或是由用户指定的类型被封装成一个对象,就可以利用辅助信息进行移植。Python也不例外,每个Python对象都有一个指向类型对象的指针和一个引用计数器。虽然方便,但也需要付出相应的代价。直接的后果是导致性能下降。不过好在Python使用的一些技术和算法为了提高处理速度允许进行相应的改良,如字符串驻留算法和自适应数乘算法等。
下面的内容引用自Python2.7.10官方文档:
PyObject
所有对象均衍生自这种基类型,这种类型包含如何将指向对象的指针亦作为对象处理的信息,这正是所Python需要的。在正常的“release”编译方式下,它仅包含对象的引用计数值以及相应指向类型对象的指针。这和由宏指令PyObject_HEAD定义的类相一致。
PyVarObject
它由PyObject扩展而来,另外增加了ob_size类,仅用于那些有长度概念的对象。这种类型在Python/C应用中不太常见。它和由宏指令PyObject_HEAD定义的类也是一致的。
不要担心不会宏指令或者不知道变量名,我们将会实现它们。
PyObject和PyVarObject结构究竟是什么呢?这里从源码中摘录了一个片段:
..\include\object.h
上述代码并不完全,我们继续探究(为了代码的清晰易懂,相较原文有所删减):
..\include\object.h
有些宏用于定义类,其他的用于初始化。
不知道你有注意到_PyObject_HEAD_EXTRA和_PyObect_EXTRA_INIT宏并没有定义了吗?事实上,全部的Python版本都是默认这样处理的。定义它们的唯一方式是使用Python编译器“Debug”一下。当然,这将会在以后进行介绍。作为教育目的,它们将以未定义的方式给出。
全部的宏都展开后,PyObject将是这个样子:
不必担心Py_ssize类型,把它想成int型就行。其他类的含义可以从词义看出来:ob_recnt为引用计数器,ob_type则是指向PyTypeObject的指针。这点稍后再谈。
现在看看PyVarObject源码吧:
可以看出来,大部分内容和PyObject是相同的,除了一个例外:ob_size,它表示可变尺寸容器所包含项目的数量(俏皮话)。
面向对象的C程序设计
至此,我想你应该明白为什么PyObject和PyVarObject(以及我们稍后将会学到的其他对象)表现出类似的特性了吧(ob_refcnt和ob_type)?
这些特性使得我们能够从底层类型抽象出共同的概念,并使我们能够以类似的方式使用各种类型,不管是简单的整形或字符串型,还是类实例,抑或切片对象。
每个Python的类型(PyIntObject,PyFloatObject以及PyDictObject)运行时都会将PyObject_HEAD作为第一个参数(或者第一个参数列表中的第一个参数,以此类推)。子对象成员的位置会被确保和全对象的位置一致。
PyObject_HEAD通常在子对象成员中出现,但只要ob_type被用于获取全部类型信息,它就能够变身为全部类型了。这种技术为C语言增色不少,尤其在轻量继承方面。
PyIntObject&PyDictObject
让我们看看实体对象PyIntObject和PyDictObject在Python中是如何运行的。
..\include\intobject.h
..\include\intobject.h
又看到PyObject_HEAD了吧?这意味着我们可以将PyIntObject看成PyObject附加了一些数据(上例中为long类型)。
同理可以查看PyDictObject对象(Python中的符号“{}”代表字典):
虽然字典类型稍微复杂一点,但我们仍可将它看做PyObject对象,就像将PyIntObject看成PyObject一样。仅仅的不同是PyDictObject增加了更多的数据。最为重要的是,这些对象被严格地定义在PyObject_HEAD之后。
学习了PyObject_HEAD的内部原理后,我们还得知道Python中的Py*Object对象,下面的代码段中的注释足以帮助你理解它的运行原理。它向你展示了Python如何界定当前所处理的类型:
为了增加代码的可读性,Python定义了大量的宏。例如,你可以使用PyInt_Check或者PyInt_CheckExact代替ob_type。类似的宏定义在每个Python对象的C文件开头找到。
字典对象“{}”:PyDict_Check和PyDict_CheckExact
函数对象:PyFunction_Check
元组对象“()”:PyTuple_Check和PyTuple_CheckExact
到现在,上面的代码就可以重写为这样了:
一些Python对象同时拥有自己的专有类型检查功能和普通类型检查功能。它们的定义在..\Include\Object.h文件中,例如:
PyTypeObject
到现在,关于PyObject未曾提及的就剩类型了。Python中的类型不仅仅是个名称(如“int”和“tuple”)和相应存储的值,还包括大量东西(例如函数,数据成员),它们若被联系到一起,将会产生一系列特性。
回忆一下PyObject_HEAD代码段:
其中的ob_type涉及到了对象类实例。让我们剖析一下(这也是我很感兴趣的地方):
..\include\dictobject.h
这并不是整体架构,但是最有意思的一部分。你或许会想,看起来怪怪的作用符func仅仅是个回调体。每个Python对象都应以一种方式初始化它。
例如,cmpfunctp_compare;明显表示它与对象之间的比较有些联系。PyIntObject对于比较函数和PyTupleObject的处理将会有所不同。
另外,hashfunctp_hash;将哈希函数定义为一种类型。例如,string将包含这一功能,但dictionary就没有。猜猜是为什么?
如果你想阅读更多相关知识,可以参阅Python/CAPIReferenceManual,"ObjectImplementationSupport","TypeObjects"一节。
接下来将对如下图所示函数在PyInt_Type,PyDict_Type和PyTuple_Type对象中的运行进行比较:
由于前三个函数拥有返回值,这提示我们,它们应用在Python抽象对象层。
抽象对象层定义了若干Python对象在运行和分类是应遵守的协议。协议指的是一类用于规定函数功能及其行为的集合。比方说一种函数当且仅当其被用作一组特殊功能(长度,尺寸,连接函数等)时被归为基于序列的类型。
现存在许多协议,我们主要看以下这些:
数字协议:全部数值类型(包括整形、浮点型、复数类型等)
序列化协议:序列化类型(包括字符串、列表、元组等)
映射协议:映射类型(字典)
回到我们的例子。
PyInt_Type
PyInt_Type执行数字协议,这也就是tp_as_sequence和tp_as_mapping函数为空的原因了。
所有的静态类型拥有专有的哈希函数,PyInt_Type也是如此(int_hash)。
PyDict_Type
Python中的字典比较微妙,虽然它是映射协议的唯一代表,但也会表现出一些序列化协议的性质(实际上函数__contains__就是一类字典键值的排序)。
由于字典类型可变,因此它没有哈希函数(仅PyObject_HashNotImplemented除外)。
PyInt_Type
元组类型也相当微妙,虽然元组基于序列化类型,但它常常遵守两种协议:序列化协议和映射协议。这也是函数tp_as_sequence和tp_as_mapping函数非空的原因了。
元组为静态对象,因此拥有哈希函数(tuplehash)。
就此,我希望你充分体会到了CPython的乐趣。虽然只是一个概述(不太深入),但对于深入了解Python内部机制还是很有帮助的。
Python培训、Python培训班、Python培训机构,就选光环大数据!
还不够过瘾?想学习更多?点击 http://hadoop.aura.cn/python/ 进行Python学习!
大数据培训、人工智能培训、Python培训、大数据培训机构、大数据培训班、数据分析培训、大数据可视化培训,就选光环大数据!光环大数据,聘请专业的大数据领域知名讲师,确保教学的整体质量与教学水准。讲师团及时掌握时代潮流技术,将前沿技能融入教学中,确保学生所学知识顺应时代所需。通过深入浅出、通俗易懂的教学方式,指导学生更快的掌握技能知识,成就上万个高薪就业学子。 更多问题咨询,欢迎点击------>>>>在线客服!