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. Thinkphp5图片上传正常,音频和视频上传失败的原因及解决

    Thinkphp5图片上传正常,音频和视频上传失败的原因及解决 一.总结 一句话总结:php中默认限制了上传文件的大小为2M,查找错误的时候百度,且根据错误提示来查找错误. 我的实际问题是: 我的表单 ...

  2. c#数据类型格式转换大全

    来源:网络 1.DateTime   数字型         System.DateTime currentTime=new System.DateTime();    1.1 取当前年月日时分秒   ...

  3. maven项目引入sqljdbc4 找不到包的完美 解决方案

    今天碰到了这个问题,解决了,顺便做一下记录.首先来 重现 一下这个问题,maven install报错,说 找不到这个包,但是其实 我已经安装了. 我们 再来 看看 maven本地仓库里面有 什么,这 ...

  4. 【Codeforces Round #428 (Div. 2) A】Arya and Bran

    [Link]: [Description] [Solution] 傻逼题 [NumberOf WA] [Reviw] [Code] #include <bits/stdc++.h> usi ...

  5. FZU 1962 新击鼓传花游戏

    新击鼓传花游戏 Time Limit: 1000ms Memory Limit: 32768KB This problem will be judged on FZU. Original ID: 19 ...

  6. 洛谷 P2867 [USACO06NOV]大广场Big Square

    P2867 [USACO06NOV]大广场Big Square 题目描述 Farmer John's cows have entered into a competition with Farmer ...

  7. Vue 学习记录<2>

    一.Vue https://vue-loader.vuejs.org/zh-cn/ https://vuejs-templates.github.io/webpack/structure.html

  8. 漫话C++之string字符串类的使用(有汇编分析)

    C++中并不提倡继续使用C风格的字符串,而是为字符串定义了专门的类,名为string. 使用前的准备工作 在使用string类型时,需要包含string头文件,且string位于std命名空间内: # ...

  9. js36---函数嵌套

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...

  10. eclipse - 下载网址

    这里面有着非常齐全的eclipse相关资源,而且都是放在网盘里面的,下载也方便 http://www.androiddevtools.cn/