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)
24

Python内部机制-PyObject对象的更多相关文章

  1. Python内部机制。

    type ,object ,__class__ ,__bases__ ,__metaclass__ , -------------------------不明白的地方----------------- ...

  2. 从底层带你理解Python中的一些内部机制

    下面博文将带你创建一个字节码级别的追踪API以追踪Python的一些内部机制,比如类似YIELDVALUE.YIELDFROM操作码的实现,推式构造列表(List Comprehensions).生成 ...

  3. Python_Mix*函数名的使用以及第一类对象,闭包,迭代器,for循环的内部机制

    一:函数名的应用(第一类对象) 函数名的命名规范和变量是一样的,函数名其实就是变量名, 0)函数名可以赋值给其他变量 def func(): #定义一个名为func的函数 print('my ange ...

  4. python与java的内存机制不一样;java的方法会进入方法区直到对象消失 方法才会消失;python的方法是对象每次调用都会创建新的对象 内存地址都不i一样

    python与java的内存机制不一样;java的方法会进入方法区直到对象消失 方法才会消失;python的方法是对象每次调用都会创建新的对象 内存地址都不i一样

  5. 《python解释器源码剖析》第6章--python中的dict对象

    6.0 序 元素和元素之间可能存在着某种关系,比如学生姓名和成绩.我希望能够通过学生的姓名找到这个学生的成绩,那么只需要将两者关联起来即可.字典正是这么做的,字典中的每个元素就是一个key:value ...

  6. 万字综述,核心开发者全面解读PyTorch内部机制

    斯坦福大学博士生与 Facebook 人工智能研究所研究工程师 Edward Z. Yang 是 PyTorch 开源项目的核心开发者之一.他在 5 月 14 日的 PyTorch 纽约聚会上做了一个 ...

  7. Python入门笔记(5):对象

    一.学习目录 1.pyhton对象 2.python类型 3.类型操作符与内建函数 4.类型工厂函数 5.不支持类型 二.思考 1.Python解释执行原理? 2.Python对象机制? 3.Pyth ...

  8. python多线程机制

    Python中的线程从一开始就是操作系统的原生线程.而Python虚拟机也同样使用一个全局解释器锁(Global Interpreter Lock,GIL)来互斥线程多Python虚拟机的使用. GI ...

  9. 【Python&数据结构】 抽象数据类型 Python类机制和异常

    这篇是<数据结构与算法Python语言描述>的笔记,但是大头在Python类机制和面向对象编程的说明上面.我也不知道该放什么分类了..总之之前也没怎么认真接触过基于类而不是独立函数的Pyt ...

随机推荐

  1. 9.9递归和动态规划(六)——打印n对括号的所有有效组合(即左右括号正确配对)

    /**  * 功能:打印n对括号的所有有效组合(即左右括号正确配对). */ 两种方法: 方法一: /** * 思路:在括号的最前面或者原有的每对括号中面插入一对括号. 至于其它任何位置.比方字符串的 ...

  2. QT就是别人好心帮你做一些枯燥,并且很重复的代码编写工作,让你更好的把精力投入到你界面的逻辑和功能的实现的功能库(否则写了上万行代码了,才写出个BUG一大堆的毛坯)

    好了,现在开始记录我学习QT的学习历程 . 本人也不是计算机专业出来的,自学了一点,但还是不好找工作,于是参加了培训,虽然感觉没多学到什么 编程的学习生涯就是不断的看别人的源码,然后自己参考着写写自己 ...

  3. js插件---tree(多级文件)插件如何使用

    js插件---tree(多级文件)插件如何使用 一.总结 一句话总结:还是一般的引入js和css后js调用的方式, 只不过tree调用的时候必须设置一个 HTML 模板(就是调用的那段html代码,别 ...

  4. 43.安装npm及cnpm(Windows)

    转自:https://www.cnblogs.com/yominhi/p/7039795.html [工具官网] Node.js : http://nodejs.cn/ 淘宝NPM: https:// ...

  5. 1.实用:Google Chrome 键盘快捷键大全

    转自:https://www.cnbeta.com/articles/soft/64070.htm 窗口和标签页快捷方式 Ctrl+N 打开新窗口 按住 Ctrl‎ 键,然后点击链接 在新标签页中打开 ...

  6. BZOJ离线版

    http://dh.attack.cf/bzoj/ 闲来无事自己搞的 可以查看权限题 至于这个东西怎么搞, 可以私信我2333 网站已经挂掉. 想看的可以去rxz大爷的blog http://ruan ...

  7. 搭建Spark源码研读和代码调试的开发环境

    转载自https://github.com/linbojin/spark-notes/blob/master/ide-setup.md 搭建Spark源码研读和代码调试的开发环境 工欲善其事,必先利其 ...

  8. css3--根据数据加载显示的一个动画

    css: .circle { width: 200px; height: 200px; position: absolute; border-radius: 50%; background: #0cc ...

  9. netty实现TCP长连接

    所用jar包 netty-all-4.1.30.Final.jar 密码:rzwe NettyConfig.java,存放连接的客户端 import io.netty.channel.group.Ch ...

  10. Python实现简单的HTTP服务器(支持文件下载)

    python内置模块 SimpleHTTPServer  (支持下载功能) 在对应的工作目录下,运行命令python -m SimpleHTTPServer 即可把当前目录下以共享服务的形式共享出去. ...