我正在尝试创建一个Python扩展模块,并实现多阶段初始化。参考之前的问题,我得到了一些建议。根据PEP 489,推荐
Py_mod_create
函数返回一个模块子类,它可能是PyModule
的子类,但我无法找到如何实现这一点。在所有尝试中,当我导入模块时,它会崩溃。如果Py_mod_create
返回其他对象(不是PyModule
子类的对象),则可以正常工作,但我不确定这是否会在未来引起问题,因为这种情况下isinstance(mymodule,types.ModuleType)
返回false。
按照内置类型子类化文档的说明,我将tp_base
设置为PyModule_Type
,并且我的tp_init
函数调用PyModule_Type.tp_init
。文档还建议在结构体开始处包含超类结构体,在这种情况下是PyModuleObject
。这个结构体在公共Python头文件中没有定义(它在Python源代码的moduleobject.c
中定义),所以现在我将PyModuleObject
字段的定义复制并粘贴到我的结构体开头。完整的代码如下:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stdio.h>
struct testmod_s {
// Fields copied from PyModuleObject in moduleobject.c
PyObject_HEAD
PyObject *md_dict;
struct PyModuleDef *md_def;
void *md_state;
PyObject *md_weaklist;
PyObject *md_name;
};
static int testmod_init(PyObject *self, PyObject *args, PyObject *kwds);
static PyObject *testmod_create(PyObject *spec, PyModuleDef *def);
static PyModuleDef_Slot testmod_slots[] = {
{Py_mod_create, testmod_create},
{0, 0} /* Sentinel */
};
static struct PyModuleDef testmod_def = {
PyModuleDef_HEAD_INIT, /* m_base */
"testmod", /* m_name */
NULL, /* m_doc */
sizeof(struct testmod_s), /* m_size */
NULL, /* m_methods */
testmod_slots, /* m_slots */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL /* m_free */
};
static PyTypeObject testmodtype = {
PyVarObject_HEAD_INIT (NULL, 0)
"testmodtype", /* tp_name */
sizeof (struct testmod_s), /* tp_basicsize */
/* fields omitted for brevity, all set to zero */
Py_TPFLAGS_DEFAULT |
Py_TPFLAGS_BASETYPE, /* tp_flags */
/* fields omitted for brevity, all set to zero */
testmod_init, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
};
PyMODINIT_FUNC
PyInit_testmod(void)
{
testmodtype.tp_base = &PyModule_Type;
if (PyType_Ready(&testmodtype)) {
return NULL;
}
PyObject *moduledef = PyModuleDef_Init(&testmod_def);
if (moduledef == NULL) {
return NULL;
}
return moduledef;
}
static int testmod_init(PyObject *self, PyObject *args, PyObject *kwds)
{
if (PyModule_Type.tp_init((PyObject *)self, args, kwds) < 0) {
return -1;
}
return 0;
}
static PyObject *testmod_create(PyObject *spec, PyModuleDef *def)
{
struct testmod_s *module = PyObject_New(struct testmod_s, &testmodtype);
if (module == NULL) {
return NULL;
}
return (PyObject *) module;
}
导入这个模块会导致segfault。我做错了什么?
我在macOS 12.0.1上使用Anaconda构建的Python 3.8.5运行:
>>> sys.version
'3.8.5 (default, Sep 4 2020, 02:22:02) \n[Clang 10.0.0 ]'
x
变量添加了 getter/setter,并且确实可以将其用作 模块属性:import testmod
print(testmod.x)
实际上调用了 getter,而testmod.x = 5
调用了 setter。 - Serge Ballesta