模块初始化函数可以直接创建并返回模块对象,称为“单阶段初始化”,使用以下两个模块创建函数中的一个:
PyObject *PyModule_Create(PyModuleDef *def)
返回值:新的引用。
根据在 def 中给出的定义创建一个新的模块对象。 它的行为类似于 PyModule_Create2() 将 module_api_version 设为 PYTHON_API_VERSION。
PyObject *PyModule_Create2(PyModuleDef *def, int module_api_version)
返回值:新的引用。 属于 稳定 ABI.
创建一个新的模块对象,在参数 def 中给出定义,设定API版本为参数 module_api_version 。如果该版本与正在运行的解释器版本不匹配,则会触发 RuntimeWarning。
备注 大多数时候应该使用 PyModule_Create() 代替使用此函数,除非你确定需要使用它。
在初始化函数返回之前,生成的模块对象通常使用 PyModule_AddObjectRef() 等函数进行填充。
多阶段初始化
指定扩展的另一种方式是请求“多阶段初始化”。 以这种方式创建的扩展模块的行为更类似 Python 模块:初始化分为 创建阶段 即创建模块对象时和 执行阶段 即填充模块对象时。 这种区分类似于类的 __new__() 和 __init__() 方法。
与使用单阶段初始化创建的模块不同,这些模块不是单例:如果移除 sys.modules 条目并重新导入模块,将会创建一个新的模块对象,而旧的模块则会成为常规的垃圾回收目标 —— 就像 Python 模块那样。 默认情况下,根据同一个定义创建的多个模块应该是相互独立的:对其中一个模块的更改不应影响其他模块。 这意味着所有状态都应该是模块对象 (例如使用 PyModule_GetState() ) 或其内容 (例如模块的 __dict__ 或使用 PyType_FromSpec() 创建的单独类) 的特定状态。
所有使用多阶段初始化创建的模块都应该支持 子解释器。保证多个模块之间相互独立,通常就可以实现这一点。
要请求多阶段初始化,初始化函数 (PyInit_modulename) 返回一个包含非空的 m_slots 属性的 PyModuleDef 实例。在它被返回之前,这个 PyModuleDef 实例必须先使用以下函数初始化:
PyObject *PyModuleDef_Init(PyModuleDef *def)
返回值:借入的引用。 属于 稳定 ABI 自 3.5 版开始.
确保模块定义是一个正确初始化的Python对象,拥有正确的类型和引用计数。
返回转换为 PyObject* 的 def ,如果发生错误,则返回 NULL。
在 3.5 版本加入.
模块定义的 m_slots 成员必须指向一个 PyModuleDef_Slot 结构体数组:
type PyModuleDef_Slot
int slot
槽位 ID,从下面介绍的可用值中选择。
void *value
槽位值,其含义取决于槽位 ID。
在 3.5 版本加入.
m_slots 数组必须以一个 id 为 0 的槽位结束。
可用的槽位类型是:
Py_mod_create
指定一个函数供调用以创建模块对象本身。 该槽位的 value 指针必须指向一个具有如下签名的函数:
PyObject *create_module(PyObject *spec, PyModuleDef *def)
该函数接受一个 ModuleSpec 实例,如 PEP 451 所定义的,以及模块定义。 它应当返回一个新的模块对象,或者设置一个错误并返回 NULL。
此函数应当保持最小化。 特别地,它不应当调用任意 Python 代码,因为尝试再次导入同一个模块可能会导致无限循环。
多个 Py_mod_create 槽位不能在一个模块定义中指定。
如果未指定 Py_mod_create,导入机制将使用 PyModule_New() 创建一个普通的模块对象。 名称是获取自 spec 而非定义,以允许扩展模块动态地调整它们在模块层级结构中的位置并通过符号链接以不同的名称被导入,同时共享同一个模块定义。
不要求返回的对象必须为 PyModule_Type 的实例。 任何类型均可使用,只要它支持设置和获取导入相关的属性。 但是,如果 PyModuleDef 具有非 NULL 的 m_traverse, m_clear, m_free;非零的 m_size;或者 Py_mod_create 以外的槽位则只能返回 PyModule_Type 的实例。
Py_mod_exec
指定一个供调用以 执行 模块的函数。 这造价于执行一个 Python 模块的代码:通常,此函数会向模块添加类和常量。 此函数的签名为:
int exec_module(PyObject *module)
如果指定了多个 Py_mod_exec 槽位,将按照它们在*m_slots*数组中出现的顺序进行处理。
Py_mod_multiple_interpreters
指定以下的值之一:
Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED
该模块不支持在子解释器中导入。
Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED
该模块支持在子解释器中导入,但是它们必须要共享主解释器的 GIL。 (参见 隔离扩展模块。)
Py_MOD_PER_INTERPRETER_GIL_SUPPORTED
该模块支持在子解释器中导入,即使它们有自己的 GIL。 (参见 隔离扩展模块。)
此槽位决定在子解释器中导入此模块是否会失败。
在一个模块定义中不能指定多个 Py_mod_multiple_interpreters 槽位。
如果未指定 Py_mod_multiple_interpreters,则导入机制默认为 Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED。
在 3.12 版本加入.
有关多阶段初始化的更多细节,请参阅PEP:489 |