问题描述
我有一个来自SWIG封装的C ++库的类的实例,我想从中提取其引用,以便能够在Cython文件中使用它,其中我直接链接到同一个C ++库通过使用更轻量级的自制Cython包装器的同一类。
我知道这不会像访问一些隐藏的属性一样容易,但我想, SWIG或CPython中的一些函数,如果从Cython(一些PyObject_ *,可能?)链接到,可能会做到这一点。不幸的是,我不知道SWIG或CPython内部是否知道如何做到这一点,或者这是否真的可能没有修改SWIG绑定的源代码。
做进一步的研究后,我想出了如何做我想要的。
根据,Python中的SWIG封装类包含三个层次:a)纯Python实例,b)自定义SwigPyObject 和c)通常不可访问的指针 void * ptr
为了访问这个指针,我不得不创建一个C ++实例, SwigPyObject结构的Cython包装器,以访问SWIG实例的内部 void * ptr
。此结构的声明通常直接包含在SWIG生成的C ++源代码中,而不是作为单独的头文件,所以我创建了一个包含它的
#include< Python.h>
typedef struct {
PyObject_HEAD
void * ptr; //这是指向实际C ++实例的指针
void * ty; // swig_type_info本来,但不要紧,
int own;
PyObject * next;
} SwigPyObject;
这个include文件随后在Cython中被引用 .pxd
文件,以允许访问内部 ptr
变量:
cdef extern fromswigpyobject.h:
ctypedef struct SwigPyObject:
void * ptr
$ b b
现在可以从 .pyx
Cython源代码中引用所需的指针:
cdef SwigPyObject * swig_obj =< SwigPyObject *> pythonswig.this
cdef MyCppClass * mycpp_ptr =< MyCppClass *?> swig_obj.ptr
//如果你想一个适当的实例而不是一个指针:
cdef MyCppClass my_instance = deref(mycpp_ptr)
:由于SWIG封装的类存在于Python和C ++空间中,SWIG实现了处理内存分配的机制,包括有关垃圾回收实例的所有权的信息。这个代码不会尝试处理任何这一点,所以可能有一个危险,跑分配问题,但只要原来的SWIG实例的引用保存在Python,我相信它应该是安全的操作它在Cython下。
I have an instance of a class from SWIG-wrapped C++ library from which I would like to extract its reference, in order to be able to use it inside a Cython file, in which I am directly linking to the same C++ library by using a more lightweight self-made Cython wrapper of the same class.
I know it would not be as easy as accessing some hidden attribute, but I imagine there might be some function within SWIG or CPython that could potentially do that if linked to from within Cython (some PyObject_*, perhaps?).
Unfortunately, I don't know enough about SWIG or CPython internals to know how to do this, or whether this is really possible without modifying the source code of the SWIG binding.
After doing further research, I have figured out how to do what I wanted.
According to the documentation, SWIG-wrapped classes in Python consist of three layers: a) a pure Python instance, b) a custom SwigPyObject built-in type contained in its .this
attribute and c) a normally inaccessible pointer void *ptr
to the actual C++ instance contained therein, which is what Cython would require.
In order to gain access to that pointer, I had to create a Cython wrapper of the SwigPyObject struct in order to access the internal void *ptr
of the SWIG instance. The declaration of this struct is normally included directly into the SWIG-generated C++ source, and not as a separate header, so I created one to contain it:
#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;
This include file is then referenced in the Cython .pxd
file, to enable access to the internal ptr
variable:
cdef extern from "swigpyobject.h":
ctypedef struct SwigPyObject:
void *ptr
The required pointer can now be referenced from inside the .pyx
Cython source code:
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)
Caveat: Since SWIG-wrapped classes exist in both Python and C++ space, SWIG implements mechanisms to deal with the memory allocation, including information about the "ownership" of an instance for garbage collection. This code doesn't try to deal with any of this, so there might be a danger of running into allocation issues, but as long as a reference to the original SWIG instance is kept in Python, I believe it should be safe to manipulate it under Cython.
这篇关于提取SWIG封装的C ++实例/指针以用于Cython的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!