问题描述
假设我们具有有关为Python编写C扩展模块的教程.现在我们要创建一个派生类型,只覆盖Noddy
的__new__()
方法.
Assume we have the type Noddy
as defined in the tutorial on writing C extension modules for Python. Now we want to create a derived type, overwriting only the __new__()
method of Noddy
.
当前,我使用以下方法(为了便于阅读而对错误进行检查):
Currently I use the following approach (error checking stripped for readability):
PyTypeObject *BrownNoddyType =
(PyTypeObject *)PyType_Type.tp_alloc(&PyType_Type, 0);
BrownNoddyType->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
BrownNoddyType->tp_name = "noddy.BrownNoddy";
BrownNoddyType->tp_doc = "BrownNoddy objects";
BrownNoddyType->tp_base = &NoddyType;
BrownNoddyType->tp_new = BrownNoddy_new;
PyType_Ready(BrownNoddyType);
这可行,但是我不确定这是否是正确的方法.我本来希望我必须设置 Py_TPFLAGS_HEAPTYPE
标志,同样,因为我在堆上动态分配了类型对象,但这样做会导致解释器出现段错误.
This works, but I'm not sure if it is The Right Way To Do It. I would have expected that I have to set the Py_TPFLAGS_HEAPTYPE
flag, too, because I dynamically allocate the type object on the heap, but doing so leads to a segfault in the interpreter.
我还考虑过使用PyObject_Call()
或类似方法显式调用type()
,但是我放弃了这个想法.我需要将函数BrownNoddy_new()
包装在Python函数对象中,并创建一个映射__new__
到此函数对象的字典,这似乎很愚蠢.
I also thought about explicitly calling type()
using PyObject_Call()
or similar, but I discarded the idea. I would need to wrap the function BrownNoddy_new()
in a Python function object and create a dictionary mapping __new__
to this function object, which seems silly.
解决此问题的最佳方法是什么?我的方法正确吗?我错过了接口功能吗?
What is the best way to go about this? Is my approach correct? Is there an interface function I missed?
有关python-dev邮件列表上的相关主题,有两个主题(1) (2).从这些线程和一些实验中,我得出结论,除非通过调用type()
分配类型,否则不应该设置Py_TPFLAGS_HEAPTYPE
.无论是手动分配类型还是调用type()
更好,这些线程中都有不同的建议.如果只有我知道包装应该放在tp_new
插槽中的C函数的推荐方法是什么,我会对后者感到满意.对于常规方法,此步骤很容易-我可以使用 PyDescr_NewMethod()
获取合适的包装对象.但是,我不知道如何为__new__()
方法创建这样的包装对象.也许我需要未记录的函数PyCFunction_New()
来创建这样的包装对象.
推荐答案
我在修改扩展以使其与Python 3兼容时遇到了相同的问题,并在尝试解决该页面时找到了此页面.
我最终确实通过阅读Python解释器的源代码来解决它, PEP 0384 和 C-API .
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
,该结构扩展了基类Noddy
的C结构.然后我们将:
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);
这篇关于如何在Python C-API中动态创建派生类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!