我有以下代码,它使用 Python 回调函数实现了一个简单的 C++ 类(ObjWithPyCallback)。这个想法是用“this”作为单个参数来调用 Python 函数。
问题是,由于 ObjWithPyCallback 是一个 SWIG 包装的对象,我需要 SWIG 类型信息才能创建一个 Python 对象。
问题在于它位于 SWIG 生成的文件“ObjWithPyCallback_wrap.cxx”中。SWIG 可以生成头文件吗?到目前为止,我还无法做到这一点。
但是,即使有头文件,SWIG 和我的主要实现之间也存在循环依赖关系,这很烦人。如果可能的话,我想找到一种方法来避免它。最终 ObjWithPyCallback 最终在与 Python 绑定不同的共享库中结束。
有没有一种干净的方法来解决这个问题?我知道这篇文章,但它只涉及 SWIG_NewPointerObj 的机制。
提前感谢您的帮助!
这是代码:
文件:example.py
import cb
def foo(x=None):
print("Hello from Foo!")
# I'd like x to be a reference to a ObjWithPyCallback object.
print(x)
o = cb.ObjWithPyCallback()
o.setCallback(foo)
o.call()
文件:ObjWithPyCallback.h
#include <Python.h>
class ObjWithPyCallback
{
public:
ObjWithPyCallback();
void setCallback(PyObject *callback);
void call();
PyObject *callback_;
};
文件:ObjWithCallback.cpp
#include "ObjWithPyCallback.h"
#include <iostream>
ObjWithPyCallback::ObjWithPyCallback() : callback_(NULL) {}
void ObjWithPyCallback::setCallback(PyObject* callback)
{
if (!PyCallable_Check(callback))
{
std::cerr << "Object is not callable.\n";
}
else
{
if ( callback_ ) Py_XDECREF(callback_);
callback_ = callback;
Py_XINCREF(callback_);
}
}
void ObjWithPyCallback::call()
{
if ( ! callback_ )
{
std::cerr << "No callback is set.\n";
}
else
{
// I want to call "callback_(*this)", how to do this cleanly?
PyObject *result = PyObject_CallFunction(callback_, "");
if (result == NULL)
std::cerr << "Callback call failed.\n";
else
Py_DECREF(result);
}
}
文件:: ObjWithPyCallback.i
%module cb
%{
#include "ObjWithPyCallback.h"
%}
%include "ObjWithPyCallback.h"