众所周知,Python是一门动态语言,OOP语言(面向对象),也是由C语言写成的。不过C语言是面向过程的,所以我一直都挺好奇Python的面向对象机制是怎么实现的。
面向对象机制
对象对于计算机来说,就是一片被分配的内存空间,这片空间可以是离散的,也可以是连续的,主要是我们一旦将这片空间称作对象,那么这片空间在使用过程中可以作为一个整体来考虑。
在Python中,对象就是为C结构体中在堆上申请的一块内存,一般来说,对象是不能初始化的,也不能在栈空间上生存,唯一例外的是类型对象(Type Object),这比较容易理解,类型对象是Python固定好的最原始的类,这些内建的Type Object都是被静态(static)初始化的。
当然Python中一个对象被创建内存的大小就是不变的了,那么为什么list,dict等对象可以实现可变长度呢?这要归功于Python约定俗成的规则——在对象中维护一个指向一块可变大小的内存区域指针。
这样做有什么好处?简单来说就是容易维护。举个简单的栗子,假设Python的list、dict的实例对象的内存挨在一起,那么当list变长时,就会覆盖了dict的内存。如果对象中有个可变大小的指针,那么将多出来的内存移动到可变区域即可,维护起来十分方便。
PyObject
在Python中所有东西都是对象,这很容易理解,int、str、list都是一个class,即对象。而且所有对象都拥有一些相同的内容,这是因为它们继承了Object,在C语言中即是PyObject,PyObject是整个Python对象机制的核心。
从代码中可以看到,整个核心都在PyOject_HEAD这个宏中。在实际发布的Python中,PyObject的定义非常简单:
- 引用计数;
- 类型信息。
在PyObject的定义中,整形变量ob_refcnt与Python的内存管理机制有关,实现了基于引用计数的垃圾收集机制。
该机制可简单理解如下:当对象A有一个新的PyObject *引用该对象时A的引用计数增加,当PyObject *被删除时,A的引用计数减少。当A的引用计数为0时,A就可以从堆上被删除,释放出内存供别的对象用。
而ob_type是一个指向_typeobject结构体的指针,这个结构体是用来指定一个对象类型的类型对象(Type Object)。
所以简而言之,所有的Python对象都必须有PyObject中的内容,这些内容将出现在每个Python对象所占有的内存的最开始的字节中。
下一次会继续讲PyObject的更多细节,欢迎关注阅读。