我有现有的C ++代码,它定义了我需要使用的一些类,但我需要能够将这些类发送到Python代码。具体来说,我需要在C ++中创建类实例,创建Python对象作为这些C ++对象的包装器,然后将这些Python对象传递给Python代码进行处理。这只是一个更大的C ++程序的一部分,因此需要使用C / Python API最终在C ++中完成。
为了让我的生活更轻松,我使用Cython来定义扩展类(cdef类),它们充当我的C ++对象的Python包装器。我使用的典型格式是cdef类包含指向C ++类的指针,然后在创建cdef类实例时对其进行初始化。因为如果我有一个现有的C ++对象要包装,我也希望能够替换指针,我已经将我的cdef类的方法添加到accept()
C ++对象并获取其指针。我的其他cdef类在Cython中成功使用accept()
方法,例如当一个对象拥有另一个对象时。
以下是我的Cython代码示例:
MyCPlus.pxd
cdef extern from "MyCPlus.h" namespace "mynamespace":
cdef cppclass MyCPlus_Class:
MyCPlus_Class() except +
PyModule.pyx
cimport MyCPlus
from libcpp cimport bool
cdef class Py_Class [object Py_Class, type PyType_Class]:
cdef MyCPlus.MyCPlus_Class* thisptr
cdef bool owned
cdef void accept(self, MyCPlus.MyCPlus_Class &indata):
if self.owned:
del self.thisptr
self.thisptr = &indata
self.owned = False
def __cinit__(self):
self.thisptr = new MyCPlus.MyCPlus_Class()
self.owned = True
def __dealloc__(self):
if self.owned:
del self.thisptr
当我尝试从C ++访问accept()
方法时出现问题。我尝试在我的cdef类和public
方法上使用api
和accept()
关键字,但我无法弄清楚如何在Cython的自动生成的{C结构中公开此方法{1}}文件。无论我尝试什么,C结构都是这样的:
.h
(由Cython自动生成)
PyModule.h
我还尝试将struct Py_Class {
PyObject_HEAD
struct __pyx_vtabstruct_11PyModule_Py_Class *__pyx_vtab;
mynamespace::MyCPlus_Class *thisptr;
bool owned;
};
输入键入为self
,我甚至尝试使用Py_Class
和Py_Class
关键字向前声明public
。我还尝试将api
作为静态方法。我尝试过的任何东西都没有用于公开accept()
方法,以便我可以在C ++中使用它。我尝试通过accept()
访问它,但是我遇到了编译器错误,“无效使用不完整类型”。我搜索了很多,但没有看到解决方案。谁能帮我?拜托,谢谢!
答案 0 :(得分:2)
正如您在comment中指出的那样,__pyx_vtab
成员似乎仅供Cython使用,因为它甚至不会在导出的标头中为其定义结构类型(或多个)。
添加回复,一种方法也可以是:
cdef api class Py_Class [object Py_Class, type Py_ClassType]:
...
cdef void accept(self, MyCPlus.MyCPlus_Class &indata):
... # do stuff here
...
cdef api void (*Py_Class_accept)(Py_Class self, MyCPlus.MyCPlus_Class &indata)
Py_Class_accept = &Py_Class.accept
基本上,我们定义一个函数指针并将其设置为我们想要公开的扩展方法。这与您的回复的cdef
功能没有多大区别;主要区别在于我们可以像往常一样在类定义中定义我们的方法,而不必复制功能或对另一个函数的方法/函数调用来公开它。需要注意的是,我们除了self
的扩展类型之外,几乎逐字地定义我们的函数指针的签名(在这种情况下) ) 等等;那么这也适用于常规功能。
请注意我在C级Cython .pyx
文件上尝试了这个,我没有,并且不打算在CPP实现文件上测试它。但是我希望这可能会起到同样的作用。
答案 1 :(得分:1)
这不是一个真正的解决方案,但我想出了解决问题的方法。我仍然希望有一个解决方案,允许我告诉Cython将accept()
方法暴露给C ++。
我的解决方法是我为Python类(不是方法)编写了一个单独的函数。然后我将api
关键字提供给我的Python类和新函数:
cdef api class Py_Class [object Py_Class, type PyType_Class]:
(etc.)
cdef api Py_Class wrap_MyCPlusClass(MyCPlus.MyCPlus_Class &indata):
wrapper = Py_Class()
del wrapper.thisptr
wrapper.thisptr = &indata
wrapper.owned = False
return wrapper
对于我需要包装的不同类的数量,这有点笨拙,但至少Cython将该函数放在易于使用的API中:
struct Py_Class* wrap_MyCPlusClass(mynamespace::MyCPlusClass &);
答案 2 :(得分:0)
在声明cpdef
时,您可能希望使用cdef
代替accept
。见the docs:
可以从Python和C中调用 *使用cpdef语句声明 *可以从任何地方调用,因为它使用了一点Cython魔法 *从其他Cython代码调用时使用更快的C调用约定。
试试吧!