当我修改扩展以与Python 3兼容时,我遇到了同样的问题,并在尝试解决它时找到了这个页面。
我最终通过阅读Python解释器的源代码解决了这个问题,PEP 0384 https://www.python.org/dev/peps/pep-0384/以及文档C-API https://docs.python.org/3/c-api/type.html?highlight=pytype_fromspec.
设置Py_TPFLAGS_HEAPTYPE
flag 告诉口译员重铸你的PyTypeObject
as PyHeapTypeObject
,其中包含也必须分配的其他成员。在某些时候,解释器会尝试引用这些额外的成员,如果您不分配它们,则会导致段错误。
Python 3.2 引入了 C 结构PyType_Slot
and PyType_Spec
和 C 函数PyType_FromSpec
简化动态类型的创建。简而言之,您使用PyType_Slot
and PyType_Spec
指定tp_*
的成员PyTypeObject
然后打电话PyType_FromSpec
完成分配和初始化内存的脏活。
从 PEP 0384 开始,我们有:
typedef struct{
int slot; /* slot id, see below */
void *pfunc; /* function pointer */
} PyType_Slot;
typedef struct{
const char* name;
int basicsize;
int itemsize;
int flags;
PyType_Slot *slots; /* terminated by slot==0. */
} PyType_Spec;
PyObject* PyType_FromSpec(PyType_Spec*);
(以上内容并非 PEP 0384 的原版,其中还包括const char *doc
作为成员PyType_Spec
。但该成员没有出现在源代码中。)
要在原始示例中使用这些,假设我们有一个 C 结构,BrownNoddy
,扩展基类的 C 结构Noddy
。那么我们就会:
PyType_Slot slots[] = {
{ Py_tp_doc, "BrownNoddy objects" },
{ Py_tp_base, &NoddyType },
{ Py_tp_new, BrownNoddy_new },
{ 0 },
};
PyType_Spec spec = { "noddy.BrownNoddy", sizeof(BrownNoddy), 0,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, slots };
PyTypeObject *BrownNoddyType = (PyTypeObject *)PyType_FromSpec(&spec);
这应该完成原始代码中的所有操作,包括调用PyType_Ready
,加上创建动态类型所需的内容,包括设置Py_TPFLAGS_HEAPTYPE
,并分配和初始化额外的内存PyHeapTypeObject
.
我希望这有帮助。