LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 247|回复: 0

创建堆分配类型

[复制链接]
发表于 2024-1-26 17:50:02 | 显示全部楼层 |阅读模式


下列函数和结构体可被用来创建 堆类型。

PyObject *PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, PyType_Spec *spec, PyObject *bases)
属于 稳定 ABI 自 3.12 版开始.
根据 spec (参见 Py_TPFLAGS_HEAPTYPE) 创建并返回一个 堆类型。

元类 metaclass 用于构建结果类型对象。 当 metaclass 为 NULL 时,元类将派生自 bases (或者如果 bases 为 NULL 则派生自 Py_tp_base 槽位,见下文)。

不支持重写 tp_new 的元类,除非 tp_new 为 NULL。 (为了向下兼容,其他 PyType_From* 函数允许这样的元类。 它们将忽略 tp_new,可能导致不完整的初始化。 这样的元类已被弃用并在 Python 3.14+ 中停止支持。)

bases 参数可被用来指定基类;它可以是单个类或由多个类组成的元组。 如果 bases 为 NULL,则会改用 Py_tp_bases 槽位。 如果该槽位也为 NULL,则会改用 Py_tp_base 槽位。 如果该槽位同样为 NULL,则新类型将派生自 object。

module 参数可被用来记录新类定义所在的模块。 它必须是一个模块对象或为 NULL。 如果不为 NULL,则该模块会被关联到新类型并且可在之后通过 PyType_GetModule() 来获取。 这个关联模块不可被子类继承;它必须为每个类单独指定。

此函数会在新类型上调用 PyType_Ready()。

请注意此函数 不能 完全匹配调用 type() 或使用 class 语句的行为。 对于用户提供的类型或元类,推荐 调用 type (或元类) 而不是 PyType_From* 函数。 特别地:

__new__() 不会在新类上被调用 (它必须被设为 type.__new__)。

__init__() 不会在新类上被调用。

__init_subclass__() 不会在任何基类上调用。

__set_name__() 不会在新的描述器上调用。

在 3.12 版本加入.

PyObject *PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
返回值:新的引用。 属于 稳定 ABI 自 3.10 版开始.
等价于 PyType_FromMetaclass(NULL, module, spec, bases)。

在 3.9 版本加入.

在 3.10 版本发生变更: 此函数现在接受一个单独类作为 bases 参数并接受 NULL 作为 tp_doc 槽位。

在 3.12 版本发生变更: 该函数现在可以找到并使用与所提供的基类相对应的元类。 在此之前,只会返回 type 实例。

元类的 tp_new 将被 忽略。 这可能导致不完整的初始化。 创建元类重写 tp_new 的类的做法已被弃用并且在 Python 3.14+ 中将不再被允许。

PyObject *PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
返回值:新的引用。 属于 稳定 ABI 自 3.3 版开始.
等价于 PyType_FromMetaclass(NULL, NULL, spec, bases)。

在 3.3 版本加入.

在 3.12 版本发生变更: 该函数现在可以找到并使用与所提供的基类相对应的元类。 在此之前,只会返回 type 实例。

元类的 tp_new 将被 忽略。 这可能导致不完整的初始化。 创建元类重写 tp_new 的类的做法已被弃用并且在 Python 3.14+ 中将不再被允许。

PyObject *PyType_FromSpec(PyType_Spec *spec)
返回值:新的引用。 属于 稳定 ABI.
等价于 PyType_FromMetaclass(NULL, NULL, spec, NULL)。

在 3.12 版本发生变更: 该函数现在可以找到并使用与 Py_tp_base 槽位中提供的基类相对应的元类。 在此之前,只会返回 type 实例。

元类的 tp_new 将被 忽略。 这可能导致不完整的初始化。 创建元类重写 tp_new 的类的做法已被弃用并且在 Python 3.14+ 中将不再被允许。

type PyType_Spec
属于 稳定 ABI (包括所有成员).
定义一个类型的行为的结构体。

const char *name
类型的名称,用来设置 PyTypeObject.tp_name。

int basicsize
如果为正数,则以字节为单位指定实例的大小。 它用于设置 PyTypeObject.tp_basicsize。

如果为零,则指定应当继承 tp_basicsize。

如果为负数,则以其绝对值指定该类的实例在超类的 基础之上 还需要多少空间。 使用 PyObject_GetTypeData() 来获取通过此方式保留的子类专属内存的指针。

在 3.12 版本发生变更: 在之前版本中,此字段不能为负数。

int itemsize
可变大小类型中一个元素的大小,以字节为单位。 用于设置 PyTypeObject.tp_itemsize。 注意事项请参阅 tp_itemsize 文档。

如果为零,则会继承 tp_itemsize。 扩展任意可变大小的类是很危险的,因为某些类型使用固定偏移量来标识可变大小的内存,这样就会与子类使用的固定大小的内存相重叠。 为了防止出错,只有在以下情况下才可以继承 itemsize:

基类不是可变大小的 (即其 tp_itemsize)。

所请求的 PyType_Spec.basicsize 为正值,表明基类的内存布局是已知的。

所请求的 PyType_Spec.basicsize 为零,表明子类不会直接访问实例的内存。

具有 Py_TPFLAGS_ITEMS_AT_END 旗标。

unsigned int flags
类型旗标,用来设置 PyTypeObject.tp_flags。

如果未设置 Py_TPFLAGS_HEAPTYPE 旗标,则 PyType_FromSpecWithBases() 会自动设置它。

PyType_Slot *slots
PyType_Slot 结构体的数组。 以特殊槽位值 {0, NULL} 来结束。

每个槽位 ID 应当只被指定一次。

type PyType_Slot
属于 稳定 ABI (包括所有成员).
定义一个类型的可选功能的结构体,包含一个槽位 ID 和一个值指针。

int slot
槽位 ID。

槽位 ID 的类名像是结构体 PyTypeObject, PyNumberMethods, PySequenceMethods, PyMappingMethods 和 PyAsyncMethods 的字段名附加一个 Py_ 前缀。 举例来说,使用:

Py_tp_dealloc 设置 PyTypeObject.tp_dealloc

Py_nb_add 设置 PyNumberMethods.nb_add

Py_sq_length 设置 PySequenceMethods.sq_length

下列 “offset” 字段不可使用 PyType_Slot 来设置:

tp_weaklistoffset (如果可能请改用 Py_TPFLAGS_MANAGED_WEAKREF)

tp_dictoffset (如果可能请改用 Py_TPFLAGS_MANAGED_DICT)

tp_vectorcall_offset (请使用 PyMemberDef 中的 "__vectorcalloffset__")

如果无法转为 MANAGED 旗标 (例如,对于 vectorcall 或是为了支持早于 Python 3.12 的版本),请在 Py_tp_members 中指定 offset。 详情参见 PyMemberDef documentation。

以下字段在创建堆类型时完全不可设置:

tp_vectorcall (请使用 tp_new 和/或 tp_init)

内部字段: tp_dict, tp_mro, tp_cache, tp_subclasses 和 tp_weaklist。

在某些平台上设置 Py_tp_bases 或 Py_tp_base 可能会有问题。 为了避免问题,请改用 PyType_FromSpecWithBases() 的 bases 参数。

在 3.9 版本发生变更: PyBufferProcs 中的槽位可能会在不受限 API 中被设置。

在 3.11 版本发生变更: 现在 bf_getbuffer 和 bf_releasebuffer 将在 受限 API 中可用。

void *pfunc
该槽位的预期值。 在大多数情况下,这将是一个指向函数的指针。

Py_tp_doc 以外的槽位均不可为 NULL。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表