cPython中的Type、Object结构体定义、内存布局

前言

cPython中,一个package、一个module,甚至一个function,都是一个类,每个类都有自己的Type类表示自己的class类型

Object

Object 所有类的C父类

Object是所有cpython中的类结构体定义的第一个成员,所有的Object都可以使用Object*指针访问Object的基本成员

/usr/include/python3.9d/object.h: 105

/* 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
    • 空 暂时没有定义 定义在此将会影响所有类
  • ob_refcnt
    • 引用计数 cpython的内存释放通过引用计数+主动回收,两种,当一个类被另一个类指针指向时候,引用+1,当一个类减少一次指向时候引用-1,当引用为0时主动释放该类
    • python中True、False、None是特殊的,这几个类在内存中永远只有一个实体,所有的True类的指向都是同一个实体
  • ob_type
    • 类 的定义,也就是 type(class)

下面是 在基类 Object 上的叠加套娃宏定义类描述了不同的类,对Object的使用,内存的布局

PyObject_VAR_HEAD

可变元素数量 比如 list/set 会使用的Object定义

也有很多明明是不可变元素数量类型,依然使用了这个结构体,比如Bool类型

/usr/include/python3.9d/object.h

/* PyObject_VAR_HEAD defines the initial segment of all variable-size
 * container objects.  These end with a declaration of an array with 1
 * element, but enough space is malloc'ed so that the array actually
 * has room for ob_size elements.  Note that ob_size is an element count,
 * not necessarily a byte count.
 */
#define PyObject_VAR_HEAD      PyVarObject ob_base;

typedef struct {
    PyObject ob_base;
    Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;
  • ob_base
    • Object 本身,描述类的type和引用计数
  • ob_size
    • 包含元素的数量

内存布局

((PyObject*)ob_base->ob_base)->ob_refcnt
((PyObject*)ob_base->ob_base)->ob_type
ob_base->ob_size

PyObject_HEAD

普通的 没有成员的Object,就是一个Object

/usr/include/python3.9d/object.h

/* PyObject_HEAD defines the initial segment of every PyObject. */
#define PyObject_HEAD                   PyObject ob_base;

Type Object 类的描述

type(object) 返回的也是一个类成员,类的所有示例,如上面的PyObject结构体描述,都有一个指向PyTypeObject的指针,描述这个object属于哪个类

/usr/include/python3.9d/object.h

typedef struct _typeobject PyTypeObject;

struct _typeobject {
    PyObject_VAR_HEAD
    const char *tp_name; /* For printing, in format "<module>.<name>" */
    Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */

    /* Methods to implement standard operations */

    destructor tp_dealloc;
    Py_ssize_t tp_vectorcall_offset;
    getattrfunc tp_getattr;
    setattrfunc tp_setattr;
    
    
    ***
    struct PyMethodDef *tp_methods;
    struct PyMemberDef *tp_members;
    struct PyGetSetDef *tp_getset;
    struct _typeobject *tp_base;
    ***
    PyObject *tp_bases;
    ***
  • tp_name
    • 类的名称
  • tp_basicsize
    • 类的结构体占用大小,对于type object则占用sizeof(_typeobject)
    • 这个大小一定是超过sizeof(PyObject)
  • tp_itemsize
    • 成员的大小
  • tp_methods
    • 类中具有的方法
  • tp_members
    • 类中具有的类的属性 (区别与实例的属性 类的属性对于所有类实例都是共同的属性指针,值一致)
  • tp_getset
    • 使用@property @set 装饰的类的属性 使用函数读取或设置类的属性
  • tp_base
    • 类的第一个父类,python支持多继承,Surper不指定基类时候使用这个
  • tp_bases
    • 类的所有父类

等等,python的部分魔术方法,init、del,均定义在这里,任意一个Object即使不声明有这些魔术方法、这些也会占用内存空间,方法的指针设置为NULL

总结

所有的类

内存布局

PyObject        类指针(类的size存储在这里,私有成员影响size)、引用计数
私有成员        
  • 类.ob_base.ob_size = sizoef(类)

type 类

type类的布局 和上述一致 只是一个源码中已实现的类

内存布局

PyObject
Py_ssize_t      通常是可变成员类才有的,不过cpython里大多数类都使用了这个成员

type的私有成员,包含一个类的魔术方法、初始化、释放、方法、属性等

延申

Class True False None 这种在内存中始终只有一份的成员,适合使用is判断,is使用c指针内存地址==进行判断,直接返回,速度更快,==使用的类的计算函数有较多步骤

print((1 == 1) is True)
print(None is None)
print(type(1) is int)

class int2(int):
    pass

print(type(int2(1)) is int)
print(type(int2(1)) is int2)
# python3 ./b.py
True
True
True
False
True
  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值