初探PyObject
首先我们再次来回顾一下,在上一篇提到过,“类”和“对象”这两个概念在Python中都是用对象实现的。“类"是一种对象,称为"类型对象”,“类"实例化得到的也是"对象”,称为"实例对象"。
实现对象机制的基石–PyObject
Python中的任何对象在C中都对应一个结构体实例,在Python中创建一个对象,等价于在C中创建一个结构体实例。所以Python中的对象本质上就是C中malloc函数为结构体实例在堆区申请的一块内存。
/* Nothing is actually declared to be a PyObject, but every pointer to
* a Python object can be cast to a PyObject*. This is inheritance built
* by hand. Similarly every pointer to a variable-size Python object can,
* in addition, be cast to PyVarObject*.
*/
typedef struct _object {
_PyObject_HEAD_EXTRA // 双向链表 垃圾回收 需要用到
Py_ssize_t ob_refcnt; // 引用计数
PyTypeObject *ob_type; // 指向类型对象的指针,决定了对象的类型
} PyObject;
_PyObject_HEAD_EXTRA是一个宏,展开后代码如下:
/* PyTypeObject structure is defined in cpython/object.h.
In Py_LIMITED_API, PyTypeObject is an opaque structure. */
typedef struct _typeobject PyTypeObject;
#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
_PyObject_HEAD_EXTRA
:这个宏是一个双向链表,Python会将程序中创建的所有对象都放入到这个双向链表中,用于跟踪所有活跃的堆对像。不过这个宏只有在debug模式下生效。
PS:带EXTRA 字样的宏 只有在debug模式下才存在
重点要关注的是另外两个变量,ob_refcnt和*ob_type。
ob_refcnt:引用计数
在PyObject的定义中,整型变量ob_refcnt与Python的内存管理机制有关,它实现了基于引用计数的垃圾收集机制。对于某一个对象A,当有一个新的PyObject*引用该对象时,A的引用计数增加。
例如:
- 对象创建
a = 123
- 变量传递使得对象被新的变量引用
a = b
- 引用该对象的某个变量作为参数传到一个函数或者类中
func(a)
- 引用该对象的某个变量作为元组、列表、集合等容器的一个元素
list = [a]
当这个PyObject*被删除时,A的引用计数减少,减少到0的时候,A就可以从堆上被删除,以释放出内存供别的对象使用。
例如:
- 引用该对象的变量被显示的销毁:
del a
- 对象的引用指向了别的对象:
a = "测试1" a = "测试2"
- 引用该对象的变量离开了它的作用域,比如函数的局部变量在函数执行完毕的时候会被销毁
- 引用该对象的变量所在的容器被销毁,或者被从容器里面删除
ob_type: 类型指针
所有的对象都是有类型的,类型对象描述实例对象的数据和行为,ob_type就是一个指向_typeobject结构体的指针,_