我有一个来自SWIG包装的C ++库的类的实例,我想从中提取它的引用,以便能够在Cython文件中使用它,我直接链接到同一个C ++库通过使用同一类更轻量级的自制Cython包装器。
我知道它不会像访问一些隐藏属性那么容易,但我想在SWIG或CPython中可能有一些函数可能会在Cython中链接到某些函数(某些PyObject_ *,也许?)。
不幸的是,我不太了解SWIG或CPython内部,知道如何做到这一点,或者如果不修改SWIG绑定的源代码,这是否真的可行。
答案 0 :(得分:2)
经过深入研究后,我发现了如何做我想做的事。
根据the documentation,Python中SWIG包装的类包含三层:a)纯Python实例,b)其.this
属性中包含的自定义SwigPyObject built-in type和c )一个通常无法访问的指针void *ptr
到其中包含的实际C ++实例,这是Cython所需要的。
为了获得对该指针的访问权限,我必须创建一个SwigPyObject结构的Cython包装器,以便访问SWIG实例的内部void *ptr
。这个结构的声明通常直接包含在SWIG生成的C ++源代码中,而不是作为一个单独的头文件,所以我创建了一个包含它的文件:
#include <Python.h>
typedef struct {
PyObject_HEAD
void *ptr; // This is the pointer to the actual C++ instance
void *ty; // swig_type_info originally, but shouldn't matter
int own;
PyObject *next;
} SwigPyObject;
然后在Cython .pxd
文件中引用此包含文件,以允许访问内部ptr
变量:
cdef extern from "swigpyobject.h":
ctypedef struct SwigPyObject:
void *ptr
现在可以从.pyx
Cython源代码中引用所需的指针:
cdef SwigPyObject *swig_obj = <SwigPyObject*>pythonswig.this
cdef MyCppClass *mycpp_ptr = <MyCppClass*?>swig_obj.ptr
// And if you want a proper instance instead of a pointer:
cdef MyCppClass my_instance = deref(mycpp_ptr)
警告:由于SWIG包装的类存在于Python和C ++空间中,SWIG实现了处理内存分配的机制,包括有关垃圾收集实例的“所有权”的信息。此代码不会尝试处理任何此类代码,因此可能存在遇到分配问题的危险,但只要在Python中保留对原始SWIG实例的引用,我相信操作它应该是安全的。在Cython下。