Python内部机制-PyObject对象
PyObject对象机制的基石
学过Python的人应该非常清晰,Python中一切都是对象,全部的对象都有一个共同的基类,对于本篇博文来说,一切皆是对象则是探索Python的对象机制的一个入口点.我如果读者在阅读本文的时候已经下载Python(Python-2.7.11)的源代码,而且已经解压进入了源代码的根文件夹下.众所周知Python是用C实现的,C是一种OO的语言。而Python是一个OOP的语言,那么怎样在C语言层面实现OOP,实现多态,这是一个有意思的话题,这也是本文须要进行探索的点.Python内部使用了一个PyObject结构体来保存全部对象共同的数据成员,以及实现GC机制所须要的一些辅助字段等.所以能够说PyObject就是Python对象机制的基石。这毫不为过.那么让我们进入到源代码中.透过源代码看看Python中的对象究竟是个啥?
PyObject对象
typedef struct _object {
PyObject_HEAD
} PyObject;
./Include/object.h
异常的简单,这一切都要归功于PyObject_HEAD宏,C语言中的宏是把双刃剑.看看PyObject_HEAD长什么样吧
#define PyObject_HEAD \
_PyObject_HEAD_EXTRA \
Py_ssize_t ob_refcnt; \
struct _typeobject *ob_type;
./Include/object.h
初看起来。还是不easy理解的,只是经验告诉我_PyObject_HEAD_EXTRA这个宏能够不用管。由于这是以下划线开头的,这类变量一般都是内部使用.为此我找到这个宏验证了我的想法.
/* Py_DEBUG implies Py_TRACE_REFS. */
#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS)
#define Py_TRACE_REFS
#endif
/* Py_TRACE_REFS implies Py_REF_DEBUG. */
#if defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG)
#define Py_REF_DEBUG
#endif
//注意看这里,仅仅有定义了Py_TRACE_REFS这个宏_PyObject_HEAD_EXTRA才不是空.
//而Py_TRACE_REFS这个宏仅仅有在Py_DEBUG有定义的情况下才会定义,可想而知 _PyObject_HEAD_EXTRA仅仅有在DEBUG模式
//才有意义,否则就是一个空.
#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
./Include/object.h
_PyObject_HEAD_EXTRA我们能够略过不看了,这个宏的作用仅仅是在DEBUG模式下,将全部的对象使用双链表链起来方便DEBUG而已.去掉_PyObject_HEAD_EXTRA后再来看看PyObject长啥样吧.
typedef struct _object {
Py_ssize_t ob_refcnt; \
struct _typeobject *ob_type;
} PyObject;
./Include/object.h
异常的清晰是不是,Py_ssize_t仅仅只是是对C语言的基本类型的一个typedef而已,这里能够觉得就是ssize_t类型了,ob_refcnt指的就是上文中说的GC机制须要的辅助字段用于维护当前对象的引用个数,ob_type是个啥呢?,这个东西说简单点就是指明当前对象是何种类型.后面会单独拿出来具体的介绍,接下来看下怎样使用PyObject来搭建整个Python的对象机制,以下是int对象的底层表示:
typedef struct {
PyObject_HEAD
long ob_ival;
} PyIntObject
./Include/intobject.h
包括了PyObject,除此之外包括了一些这些对象特有的一些数据成员,比方这里的ob_ival。就是用来保存int对象的具体数值的.那么String对象可想而知应该有一个char*的指针指向一段heap的内存空间,还须要有一个数据成员来保存当前的String的字符个数,那么list对象呢?,dict对象呢?,细想一下这些对象都应该包括一个指明当前对象包括的元素的个数的数据成员,好吧,这里我们找到了一些共同点。到这里产生了一个技术问题的抉择了,int对象不须要有指明当前对象包括元素个数的数据成员,而string对象,list对象,dict对象都须要有,那么这个数据成员应该放在PyObject中,还是归为每一个对象自己特有的数据成员呢?,Python选择了前者将这个数据成员放到了PyObject中。但又没全然这样做.这一切都归功于Python中的另外一个概念,可变对象和不可变对象.以下通过源代码我们来看看Python究竟是怎么做的
PyVarObject对象
typedef struct {
PyObject_VAR_HEAD
} PyVarObject;
./Include/object.h
弄了一个PyVarObject对象出来了,事实上这是一个所谓的纸老虎。打开PyObject_VAR_HEAD这个宏你就会发现真相原来是这样.
#define PyObject_VAR_HEAD \
PyObject_HEAD \
Py_ssize_t ob_size; /* Number of items in variable part */
./Include/object.h
又是异常的简单。就是在原有的PyObject基础上加了一个ob_size成员,用来指明当前对象所拥有的元素个数.可是有一个须要注意就是ob_size数据成员的位置仅仅能在PyObject_HEAD以下,目的是为了能够通过PyObject强制转换成不论什么一个对象.如果你不明确,那么来张图看看.
回到Python
源代码看完了,是不是有点想大展宏图的冲动。可惜依照我们眼下的水平。相对Python做些什么恐怕还不够格。只是我们能够利用Python来验证下我们读源代码的收获.通过上文分析的PyObject,还有PyIntObject。我们来计算一下一个PyIntObject大小。
typedef struct {
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
long ob_ival;
} PyIntObject
一个ob_refcnt这是一个ssize_t类型,64为系统下是8个字节,一个ob_type是个指针,在64位系统下相同也是8个字节,一个long类型在64位系统下相同也是8个字节所以算起来一个PyIntObject是24个字节,回到Python中我们来验证一下:
>>> import sys
>>> inttype = 1
>>> sys.getsizeof(inttype)
24Python内部机制-PyObject对象的更多相关文章
- Python内部机制。
type ,object ,__class__ ,__bases__ ,__metaclass__ , -------------------------不明白的地方----------------- ...
- 从底层带你理解Python中的一些内部机制
下面博文将带你创建一个字节码级别的追踪API以追踪Python的一些内部机制,比如类似YIELDVALUE.YIELDFROM操作码的实现,推式构造列表(List Comprehensions).生成 ...
- Python_Mix*函数名的使用以及第一类对象,闭包,迭代器,for循环的内部机制
一:函数名的应用(第一类对象) 函数名的命名规范和变量是一样的,函数名其实就是变量名, 0)函数名可以赋值给其他变量 def func(): #定义一个名为func的函数 print('my ange ...
- python与java的内存机制不一样;java的方法会进入方法区直到对象消失 方法才会消失;python的方法是对象每次调用都会创建新的对象 内存地址都不i一样
python与java的内存机制不一样;java的方法会进入方法区直到对象消失 方法才会消失;python的方法是对象每次调用都会创建新的对象 内存地址都不i一样
- 《python解释器源码剖析》第6章--python中的dict对象
6.0 序 元素和元素之间可能存在着某种关系,比如学生姓名和成绩.我希望能够通过学生的姓名找到这个学生的成绩,那么只需要将两者关联起来即可.字典正是这么做的,字典中的每个元素就是一个key:value ...
- 万字综述,核心开发者全面解读PyTorch内部机制
斯坦福大学博士生与 Facebook 人工智能研究所研究工程师 Edward Z. Yang 是 PyTorch 开源项目的核心开发者之一.他在 5 月 14 日的 PyTorch 纽约聚会上做了一个 ...
- Python入门笔记(5):对象
一.学习目录 1.pyhton对象 2.python类型 3.类型操作符与内建函数 4.类型工厂函数 5.不支持类型 二.思考 1.Python解释执行原理? 2.Python对象机制? 3.Pyth ...
- python多线程机制
Python中的线程从一开始就是操作系统的原生线程.而Python虚拟机也同样使用一个全局解释器锁(Global Interpreter Lock,GIL)来互斥线程多Python虚拟机的使用. GI ...
- 【Python&数据结构】 抽象数据类型 Python类机制和异常
这篇是<数据结构与算法Python语言描述>的笔记,但是大头在Python类机制和面向对象编程的说明上面.我也不知道该放什么分类了..总之之前也没怎么认真接触过基于类而不是独立函数的Pyt ...
随机推荐
- IOS 一句代码搞定启动引导页
前言引导页,一个酷炫的页面,自从微博用了之后一下就火起来了,对于现在来说一个app如果没有引导页似乎总显那么不接地气,那么为了让我们的app也“高大上”一次,我写了一个demo来实现启动引导页的实现, ...
- HDU 6182 A Math
A Math Problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)To ...
- fg、bg、jobs、&、 ctrl+z---系统任务
系统任务有关的命令 一.& 这个用在一个命令的最后,可以把这个命令放到后台执行 二.ctrl + z 可以将一个正在前台执行的命令放到后台,并且暂停 一和二的区别(&放入后 ...
- javascript 获取HTML DOM父,子,临近节点
在Web应用程序特别是Web2.0程序开发中.常常要获取页面中某个元素,然后更新该元素的样式.内容等.怎样获取要更新的元素,是首先要解决的问题.令人欣慰的是,使用JavaScript获取节点的方法有非 ...
- 【hoj】2160 bin packing 二分、贪心
这个题是在二分的题单上的,可是依据二分法写出来的会在oj上超时.依据题目以下给出的提示能够发现能通过贪心法每次都找最能满足的情况去填充每个包,这样就能保证使用的包的数量是最少的 二分法解法: #inc ...
- 源代码编译安装CloudStack 4.2
基于CentOS 6.4安装CloudStack 环境配置 # yum -y update # yum -y upgrade 安装NTP,jdk 1.7, tomcat 6, mysql,git等服务 ...
- 跟着辛星用PHP的反射机制来实现插件
我的博文的前一篇解说了PHP的反射机制是怎么回事,假设读者还不清楚反射机制,能够搜索下或者看我的博文,都是不错的选择.我们開始解说一下怎么用PHP来实现插件机制.所谓插件机制.就是我们定义一个接口.即 ...
- git 工具的使用总结(6)-提交合并处理
1.撤消修改 1)revert:反转提交,它就是把你的一个提交先撤消掉,但是,它跟reset不同的是,你的这次这小会留下记录,这样在你下次需要的时候,可以通过这个节点把撤消的提交恢复 zhangshu ...
- php数组时按值传递还是按地址传递
php数组时按值传递还是按地址传递 一.总结 1.数组都是按值:php普通变量和数组的赋值(=)是按值传递,对象的赋值(=)是按址传递 2.对象和按值和按址:对象的clone(用clone关键字)是按 ...
- Flume的data flow(数据流)
data flow描述了数据从产生,传输.处理并最终写入目标的一条路径. 数据的采集的流向!如下图所示.