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 ...
随机推荐
- vim 实际行跟屏幕行移动命令
我们使用vim的时候,经常会碰到那种情况,就是我们输入的内容过长,中间一直不换行.当我们一行的长度超出电脑屏幕的时候,我们会发现这时候文字自动换行了.不过,如果你使用行号看的话,其实这新的一行是没有行 ...
- amaze ui响应式辅助
amaze ui响应式辅助 响应式辅助 就是不同的显示屏幕,或者手机的横竖屏,你可以控制栏目的显影,还是挺有帮助的 视口大小 .am-[show|hide]-[sm|md|lg][-up|-down| ...
- c++值传递,指针传递,引用传递以及指针与引用的区别
值传递: 形参是实参的拷贝,改变形参的值并不会影响外部实参的值.从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入, 不能传出.当函数内部需要修改参数,并且不希望这个改变影 ...
- POJ 3038 贪心(multiset)
题意: 思路: 1. 贪心 我们考虑肯定是走最近的最合适 想象自己是一个黑一日游的司机: 1.如果有乘客要上车,那么就让他上,收钱! 2.如果超载了,把距目的地最远的几个乘客踢下去,退钱. 3.行驶到 ...
- JQ 实施编辑 (clone()复制行||双击编辑)
//代码 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <titl ...
- VMware Vsphere 6.0安装部署 Vsphere ESXi安装
Vsphere ESXi安装 ESXi作为虚拟化环境的Hypervisor层,负责将服务器虚拟成资源池,提供接口供管理组件调用,将下面的iso刻录成光盘或可启动U盘,安装在服务器裸机上: 下载地址请见 ...
- lastlog---显示系统中所有用户最近一次登录信息。
lastlog命令用于显示系统中所有用户最近一次登录信息. lastlog文件在每次有用户登录时被查询.可以使用lastlog命令检查某特定用户上次登录的时间,并格式化输出上次登录日志/var/log ...
- Java设计模式23种(搞笑版) (转)
昨天做了一下支付宝的笔试题目被打击了,大量的逻辑推理和数学规律运算题目,其中还有问道Java设计模式的题目,一点都不知道,今天看到一份不错的介绍,非常好理解,作者是谁我没有办法考证,但是所有权 ...
- apache wicket 7.X之HelloWorld
Wicket是什么 Wicket一个开发Java Web应用程序框架. 它使得开发web应用程序变得easy而轻松. Wicket利用一个POJO data beans组件使得它能够与不论什么持久层技 ...
- hdu1874 畅通project续 最短路 floyd或dijkstra或spfa
Problem Description 某省自从实行了非常多年的畅通project计划后.最终修建了非常多路.只是路多了也不好,每次要从一个城镇到还有一个城镇时,都有很多种道路方案能够选择.而某些方案 ...