假设我们有在tutorial on writing C extension modules for Python中定义的Noddy
类型。现在我们要创建一个派生类型,只覆盖__new__()
方法。在
目前我使用以下方法(删除可读性的错误检查):
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);
这是可行的,但我不确定这是不是正确的方法。我本以为我也必须设置^{
我还考虑过使用PyObject_Call()
或类似的方法显式地调用type()
,但是我放弃了这个想法。我需要将函数BrownNoddy_new()
包装在Python函数对象中,并创建一个字典映射__new__
到这个函数对象,这看起来很愚蠢。在
最好的办法是什么?我的方法正确吗?我错过了一个接口功能吗?在
在python dev邮件列表(1)(2)上有两个主题。从这些线程和一些实验中,我推断我不应该设置Py_TPFLAGS_HEAPTYPE
,除非通过调用type()
来分配类型。这些线程中有不同的建议,无论是手动分配类型还是调用type()
。如果我知道包装应该放在tp_new
槽中的C函数的推荐方法是什么,我会很乐意使用后者。对于常规方法,这一步很容易——我可以使用^{__new__()
方法创建这样一个包装器对象——也许我需要一个未记录的函数PyCFunction_New()
来创建这样的包装器对象。在
尝试并理解如何做到这一点的一个方法是使用SWIG创建它的一个版本。看看它产生了什么,看看它是否匹配或是以不同的方式完成。据我所知,编写SWIG的人对扩展Python有着深入的理解。无论如何,看看他们是怎么做事的。它可以帮助你理解这个问题。在
我在修改扩展以与python3兼容时遇到了同样的问题,并在试图解决它时找到了这个页面。在
我最终通过阅读Python解释器的源代码PEP 0384和{a2}的文档解决了这个问题。在
设置
Py_TPFLAGS_HEAPTYPE
标志会告诉解释器将您的PyTypeObject
重新转换为PyHeapTypeObject
,其中包含必须分配的其他成员。在某些时候,解释器试图引用这些额外的成员,如果您不分配它们,它将导致segfault。在python3.2引入了C结构}以及简化动态类型创建的C函数
PyType_Slot
和{PyType_FromSpec
。简而言之,使用PyType_Slot
和PyType_Spec
来指定PyTypeObject
的tp_*
成员,然后调用PyType_FromSpec
来完成分配和初始化内存的繁琐工作。在根据PEP 0384,我们有:
(以上不是pep0384的文本副本,它还包括}的成员。但源代码中没有该成员。)
const char *doc
作为{为了在原始示例中使用这些,假设我们有一个C结构,
^{pr2}$BrownNoddy
,它扩展了基类Noddy
的C结构。那么我们就可以:这应该完成原始代码中的所有操作,包括调用
PyType_Ready
,以及创建动态类型所需的操作,包括设置Py_TPFLAGS_HEAPTYPE
,为PyHeapTypeObject
分配和初始化额外内存。在我希望这对你有帮助。在
如果这个答案很糟糕,我很抱歉,但是您可以在PythonQt中找到这个想法的实现,特别是我认为以下文件可能是有用的参考:
来自PythonQtClassWrapper_init的这段代码让我觉得有点有趣:
值得注意的是PythonQt确实使用了包装器生成器,因此它并不完全符合您的要求,但我个人认为,试图超过vtable并不是最理想的设计。基本上,Python有许多不同的C++包装生成器,人们用它们来做一个很好的理由——它们被记录下来,在搜索结果和堆栈溢出中到处都有例子。如果你手动推出一个以前没人见过的解决方案,那么如果他们遇到问题,他们调试起来就会困难得多。即使是封闭源代码,下一个要维护它的人也会抓狂,你必须向每一个新来的人解释。在
< >一旦你得到一个代码生成器,你所需要做的就是维护底层C++代码,你不必手工更新或修改扩展代码。(这可能离你提出的诱人解决方案不太远)建议的解决方案是一个破坏新引入的PyCapsule提供a bit more protection的类型安全性的示例(当按照指示使用时)。在
因此,虽然这样实现派生/子类可能不是最好的长期选择,而是包装代码,让vtable做它最擅长的事情,当新用户有问题时,您可以让他指向whateversolutionfitsbest的文档。在
不过,这只是我的看法。:天
相关问题 更多 >
编程相关推荐