提取 SWIG 包装的 C++ instance/pointer 以在 Cython 中使用
Extracting SWIG wrapped C++ instance/pointer for use in Cython
我有一个来自 SWIG 包装的 C++ 库的 class 实例,我想从中提取它的引用,以便能够在我直接在其中的 Cython 文件中使用它通过使用相同 class.
的更轻量级自制 Cython 包装器链接到相同的 C++ 库
我知道这不像访问某些隐藏属性那么容易,但我想如果从 Cython 中链接到 SWIG 或 CPython 中可能有一些函数可能会这样做(也许是一些 PyObject_*?) .
不幸的是,我对 SWIG 或 CPython 的内部知识了解不够,不知道如何做到这一点,或者这是否真的可行而不修改 SWIG 绑定的源代码。
经过进一步研究,我想出了如何做我想做的事。
根据其 .this
属性中包含的 the documentation, SWIG-wrapped classes in Python consist of three layers: a) a pure Python instance, b) a custom SwigPyObject built-in type 和 c) 通常无法访问的指针 void *ptr
指向其中包含的实际 C++ 实例,这正是 Cython 所需要的。
为了访问该指针,我必须创建 SwigPyObject 结构的 Cython 包装器,以便访问 SWIG 实例的内部 void *ptr
。此结构的声明通常直接包含在 SWIG-generated C++ 源代码中,而不是作为单独的 header,因此我创建了一个包含它的文件:
#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-wrapped 类 存在于 Python 和 C++ space 中,SWIG 实现了处理内存分配的机制,包括有关 [=垃圾实例的 32=] collection。此代码不会尝试处理任何这些,因此可能存在 运行 分配问题的危险,但只要在 Python 中保留对原始 SWIG 实例的引用,我相信在 Cython 下操作它应该是安全的。
我有一个来自 SWIG 包装的 C++ 库的 class 实例,我想从中提取它的引用,以便能够在我直接在其中的 Cython 文件中使用它通过使用相同 class.
的更轻量级自制 Cython 包装器链接到相同的 C++ 库我知道这不像访问某些隐藏属性那么容易,但我想如果从 Cython 中链接到 SWIG 或 CPython 中可能有一些函数可能会这样做(也许是一些 PyObject_*?) .
不幸的是,我对 SWIG 或 CPython 的内部知识了解不够,不知道如何做到这一点,或者这是否真的可行而不修改 SWIG 绑定的源代码。
经过进一步研究,我想出了如何做我想做的事。
根据其 .this
属性中包含的 the documentation, SWIG-wrapped classes in Python consist of three layers: a) a pure Python instance, b) a custom SwigPyObject built-in type 和 c) 通常无法访问的指针 void *ptr
指向其中包含的实际 C++ 实例,这正是 Cython 所需要的。
为了访问该指针,我必须创建 SwigPyObject 结构的 Cython 包装器,以便访问 SWIG 实例的内部 void *ptr
。此结构的声明通常直接包含在 SWIG-generated C++ 源代码中,而不是作为单独的 header,因此我创建了一个包含它的文件:
#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-wrapped 类 存在于 Python 和 C++ space 中,SWIG 实现了处理内存分配的机制,包括有关 [=垃圾实例的 32=] collection。此代码不会尝试处理任何这些,因此可能存在 运行 分配问题的危险,但只要在 Python 中保留对原始 SWIG 实例的引用,我相信在 Cython 下操作它应该是安全的。