次のコードがあります。これは、Pythonコールバック関数を使用して単純なC ++クラス(ObjWithPyCallback)を実装します。アイデアは、「this」を単一の引数としてPython関数を呼び出すことです。
問題は、ObjWithPyCallbackがSWIGでラップされたオブジェクトであるため、Pythonオブジェクトを作成するためにSWIGtypeinfoが必要なことです。
これに伴う問題は、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"