【发布时间】:2012-09-12 16:34:13
【问题描述】:
我有以下代码,它使用 Python 回调函数实现了一个简单的 C++ 类 (ObjWithPyCallback)。这个想法是用“this”作为单个参数来调用 Python 函数。
问题在于,由于 ObjWithPyCallback 是一个 SWIG 包装的对象,我需要 SWIG 类型信息才能创建一个 Python 对象。
问题在于它位于 SWIG 生成的文件“ObjWithPyCallback_wrap.cxx”中。 SWIG 可以生成头文件吗?到目前为止,我还无法做到这一点。
但是,即使使用头文件,SWIG 和我的主要实现之间也存在循环依赖关系,这很烦人。如果可能的话,我想找到一种方法来避免它。最终,ObjWithPyCallback 会在与 Python 绑定不同的共享库中结束。
有没有一种干净的方法来解决这个问题?我知道this post,但它只解决了 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"
【问题讨论】:
-
我已经通过继承(在 Python 中创建的派生类中使用 Python 版本覆盖的 C++ 虚函数)完成了这项工作,但是直接提供了类似的回调函数。