提取SWIG包装的C ++实例/指针,以便在Cython中使用

时间:2015-03-06 17:14:24

标签: python c++ swig cython cpython

我有一个来自SWIG包装的C ++库的类的实例,我想从中提取它的引用,以便能够在Cython文件中使用它,我直接链接到同一个C ++库通过使用同一类更轻量级的自制Cython包装器。

我知道它不会像访问一些隐藏属性那么容易,但我想在SWIG或CPython中可能有一些函数可能会在Cython中链接到某些函数(某些PyObject_ *,也许?)。

不幸的是,我不太了解SWIG或CPython内部,知道如何做到这一点,或者如果不修改SWIG绑定的源代码,这是否真的可行。

1 个答案:

答案 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下。