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

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

不幸的是,我对 SWIG 或 CPython 内部的了解不够,不知道如何做到这一点,或者在不修改 SWIG 绑定(bind)的源代码的情况下这是否真的可行。

最佳答案

经过进一步的研究,我想出了如何做我想做的事。

根据 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)

警告:由于 Python 和 C++ 空间中都存在 SWIG 包装的类,因此 SWIG 实现了处理内存分配的机制,包括有关垃圾收集实例的“所有权”的信息。这段代码不会尝试处理任何这些,因此可能存在遇到分配问题的危险,但是只要在 Python 中保留对原始 SWIG 实例的引用,我相信操作它应该是安全的在 Cython 下。

关于python - 提取 SWIG 包装的 C++ 实例/指针以在 Cython 中使用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28904033/

10-16 22:27