python 内核分析(二):PyObject,对象的基础

本系列作为本人@takooctopus深入学习python机制的记录,这个博客遵照着栖迟于一丘的博客上面的流程进行的,也包含我在实际查看源码时的感想,特此列出,表示感谢。

PyObject,对象的基础

PyObject的定义

我们就用官方里面的解释:
没有什么能被完全被声明为一个PyObject,但每一个指向Python的对象的指针均能够被视为一个PyObject* 指针。


{{- code -}}

_PyObject_HEAD_EXTRA

再接着我们看里面的第一个属性_PyObject_HEAD_EXTRA,追踪到
其也定义在object.h里面:


{{- code -}}

其表示我们如果定义了Py_TRACE_REFS的话,这个结构将可以支持双向列表,并且所有堆中的活动均在这个列表中

因为在 release 下没有定义Py_TRACE_REFS,我们可以忽略这个宏

Py_ssize_t

接着我们追踪Py_ssize_t这个属性


{{- code -}}

关于HAVE_SSIZE_T
查到对于HAVE_SSIZE_T的默认定义为1,其定义在 pyconfig.h

关于ssize_t
即我们默认下,根据平台将ssize_t的类型设置为__int64或者_W64


{{- code -}}

关于Py_intptr_t
我们继续看Py_intptr_t其实是由intptr_t定义的


{{- code -}}

我们继续看intptr_t
其又在 Include/vcstdint.h 中被定义了:


{{- code -}}

我们看到其在64位系统中是64位的int,而32位系统是_W64,我们可以看到Py_ssize_t的本质为一个int

此时,我们就可以简化我们所看见的对象了


{{- code -}}

成员作用:

  • ob_refcnt:counter,对于变量引用次数进行计数,关于垃圾清理。
  • ob_type:type,储存了对象的类型信息,如int,string,或是function

除此之外,这个作为一个基本单元,在实际使用时还需要其他的内容

我们以 PyLongObject 为例:


{{- code -}}

其第一个属性PyObject_VAR_HEADPyVarObjectob_base组成
第二个属性由digit构成

变长对象和定长对象

在c语言中, 整型占用内存大小是固定的, 无论你保存1还是100. 而由于c没有字符串类型, 因此要表示字符串得用N个char组成数组. 在python中这样描述变长对象:


{{- code -}}

ob_size 表示容纳元素的个数, 不是对象占用的内存字节数.

int string list dict
ob_refnt ob_refnt ob_refnt ob_refnt
ob_type ob_type ob_type [others]
[NULL] [others] [others] [NULL]

类型对象


{{- code -}}

_typeobject 中包含了很多信息,主要有:

  • 1.类型名,tp_name,格式为 <module>.<name> ,用于内部调用和方便调试
  • 2.创建对象时分配内存空间大小的变量,tp_basicsizetp_itemsize,分别代表基本的大小和里面元素的大小
  • 3.与对象相关的操作,如tp_print这样的函数
  • 4.要描述的本类型的其他信息