gpt4 book ai didi

c++ - 使用 SWIG 包装对象从 C++ 调用 Python 函数的最简洁方法是什么

转载 作者:IT老高 更新时间:2023-10-28 23:14:44 26 4
gpt4 key购买 nike

我有以下代码,它使用 Python 回调函数实现了一个简单的 C++ 类 (ObjWithPyCallback)。这个想法是用“this”作为单个参数来调用 Python 函数。

问题在于,由于 ObjWithPyCallback 是一个 SWIG 包装的对象,我需要 SWIG 类型信息才能创建一个 Python 对象。

问题在于它位于 SWIG 生成的文件“ObjWithPyCallback_wrap.cxx”中。 SWIG 可以生成头文件吗?到目前为止,我还无法做到这一点。

但是,即使使用头文件,SWIG 和我的主要实现之间也存在循环依赖关系,这很烦人。如果可能的话,我想找到一种方法来避免它。最终,ObjWithPyCallback 会在与 Python 绑定(bind)不同的共享库中结束。

有没有一种干净的方法来解决这个问题?我知道 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"

最佳答案

以下是我解决此问题的有效解决方案。它使用了上述@omnifarious 和@flexo 的建议。

特别是我们创建了一个带有 SWIG 导向器的回调类,然后在 Python 中从它派生以获得所需的回调功能,而不引入循环依赖。

此外,我们提供了一个接口(interface),它允许任何可调用的 Python 对象充当回调。我们通过使用 SWIG 中的“pythonpred”指令将一些代码添加到“setCallback”函数来实现这一点。此代码仅检查可调用对象,如果找到,则将其包装在 Callback 实例中。

最后,我们处理与让 C++ 类 (ObjWithPyCallback) 引用导演对象(即 Callback 的子类)相关的内存问题。

文件example.py:

import cb

class CB(cb.Callback):
def __init__(self):
super(CB, self).__init__()
def call(self, x):
print("Hello from CB!")
print(x)

def foo(x):
print("Hello from foo!")
print(x)

class Bar:
def __call__(self, x):
print("Hello from Bar!")
print(x)


o = cb.ObjWithPyCallback()
mycb=CB()
o.setCallback(mycb)
o.call()
o.setCallback(foo)
o.call()
o.setCallback(Bar())
o.call()

文件 ObjWithPyCallback.i:

%module(directors="1") cb
%{
#include "Callback.h"
#include "ObjWithPyCallback.h"
%}
%feature("director") Callback;
%feature("nodirector") ObjWithPyCallback;

%feature("pythonprepend") ObjWithPyCallback::setCallback(Callback&) %{
if len(args) == 1 and (not isinstance(args[0], Callback) and callable(args[0])):
class CallableWrapper(Callback):
def __init__(self, f):
super(CallableWrapper, self).__init__()
self.f_ = f
def call(self, obj):
self.f_(obj)

args = tuple([CallableWrapper(args[0])])
args[0].__disown__()
elif len(args) == 1 and isinstance(args[0], Callback):
args[0].__disown__()


%}

%include "Callback.h"
%include "ObjWithPyCallback.h"

文件回调.h:

#ifndef CALLBACK_H
#define CALLBACK_H

class ObjWithPyCallback;

class Callback
{
public:
Callback(){}

virtual ~Callback(){}
virtual void call(ObjWithPyCallback& object){}
};

#endif

文件 ObjWithPyCallback.h:

#ifndef OBJWITHPYCALLBACK_H
#define OBJWITHPYCALLBACK_H

class Callback;

class ObjWithPyCallback
{
public:

ObjWithPyCallback();
~ObjWithPyCallback();
void setCallback(Callback &callback);
void call();

private:

Callback* callback_;
};

#endif

文件 ObjWithPyCallback.cpp:

#include "ObjWithPyCallback.h"
#include "Callback.h"

#include <iostream>

ObjWithPyCallback::ObjWithPyCallback() : callback_(NULL) {}

ObjWithPyCallback::~ObjWithPyCallback()
{
}

void ObjWithPyCallback::setCallback(Callback &callback)
{
callback_ = &callback;
}

void ObjWithPyCallback::call()
{
if ( ! callback_ )
{
std::cerr << "No callback is set.\n";
}
else
{
callback_->call(*this);
}
}

关于c++ - 使用 SWIG 包装对象从 C++ 调用 Python 函数的最简洁方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12392703/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com