首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用c++为pybind11设置python函数作为回调?

如何使用c++为pybind11设置python函数作为回调?
EN

Stack Overflow用户
提问于 2022-01-06 07:37:07
回答 2查看 815关注 0票数 2
代码语言:javascript
复制
typedef bool (*ftype_callback)(ClientInterface* client, const Member* member ,int member_num);

struct Member{
    char x[64];
    int y;
};

class ClientInterface {
public: 
    virtual int calc()=0;
    virtual bool join()=0;
    virtual bool set_callback(ftype_callback on_member_join)=0;
};

它来自于SDK,我可以在client代码中从动态库中调用它。

代码语言:javascript
复制
bool cb(ClientInterface* client, const Member* member ,int member_num) {
    // do something
}
cli->set_callback(cb);
cli->join();

我希望使用pybind11将其移植到python绑定。如何在python中使用set_callback

我看过文档,并试着:

代码语言:javascript
复制
PYBIND11_MODULE(xxx, m) {
    m.def("set_callback", [](xxx &self, py::function cb ){
        self.set_callback(cb);
    });
}

代码刚刚编译失败。

我的问题是,如何将py::function转换为ftype_callback,或者有其他方法来实现它?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-01-13 22:50:10

你需要一点C++才能让事情顺利进行。我要用一个更简单的结构来让答案更易读。在绑定代码中:

代码语言:javascript
复制
#include <pybind11/pybind11.h>

#include <functional>
#include <string>

namespace py = pybind11;

struct Foo
{
    int i;
    float f;
    std::string s;
};

struct Bar
{
    std::function<bool(const Foo &foo)> python_handler;
    std::function<bool(const Foo *foo)> cxx_handler;

    Bar()
    {
        cxx_handler = [this](const Foo *foo) { return python_handler(*foo); };
    }
};

PYBIND11_MODULE(example, m)
{
    py::class_<Foo>(m, "Foo")  //
        .def_readwrite("i", &Foo::i)
        .def_readwrite("f", &Foo::f)
        .def_readwrite("s", &Foo::i);

    py::class_<Bar>(m, "Bar")  //
        .def_readwrite("handler", &Bar::python_handler);
}

在这里,Foo是传递给回调的对象,Bar是需要它的回调函数集的对象。由于您使用指针,所以我已经将python_handler函数包装为cxx_handler,这意味着要在C++中使用,并将指针转换为引用。

为了完整地完成,我将在这里给出一个模块使用的可能示例:

代码语言:javascript
复制
import module.example as impl

class Bar:
    def __init__(self):
        self.bar = impl.Bar()
        self.bar.handler = self.handler
        
    def handler(self, foo):
        print(foo)
        return True

我已经在我的一个项目中成功地使用了这个结构。我不知道您想如何进行,但是如果您不想更改您的原始结构,您可以在它们上编写使用给定结构的包装类。

更新:

当我写上面的答案时,我以为你控制了这个结构(我会把它留给任何需要它的人)。如果您有一个cli实例,则可以执行以下操作:

代码语言:javascript
复制
using Handler = std::function<bool(std::string, int, int)>;

Handler handler;

bool cb(ClientInterface *client, const Member *member, int member_num)
{
    return handler(std::string(member->x), member->y, member_num);
}

// We have created cli somehow

// cli->set_callback(cb);

// cli->join();

PYBIND11_MODULE(example, m)
{
    m.def("set_callback", [](Handler h) { handler = h; });
}

如果有多个ClientInterface实例,则可以将ClientInterface指针映射到处理程序,并根据给定的ClientInterface指针在cb函数中调用适当的处理程序。

注意:我还没有用python脚本测试上面的内容,但是它应该能工作。

另一次更新

如果要处理多个实例,代码大致可以如下所示:

代码语言:javascript
复制
using Handler = std::function<bool(std::string, int, int)>;

std::map<ClientInterface *, handler> map;

bool cb(ClientInterface *client, const Member *member, int member_num)
{
    // Check if <client> instance exists in map
    return map[client](std::string(member->x), member->y, member_num);
}

PYBIND11_MODULE(example, m)
{
    m.def("set_callback", [](int clientid, Handler h) 
    {
        // Somehow map <clientid> to <client> pointer
        map[client] = h;
    });
}

注意,这不是一个可运行的代码,您需要完成它。

票数 2
EN

Stack Overflow用户

发布于 2022-09-02 02:04:14

您可以在pybind11中使用python类型获取数据。

确保你有#include <pybind11/functional.h>

代码语言:javascript
复制
// c++
using PyCallback = std::function<void(pybind11::bytearray)>;

class Haha
{
public:
    void setCallback(PyCallback& pyfn) {
        m_pyfn = pyfn;
    }
    void onDataAvaiable(char* buf, int len) {
        m_pyfn(pybind11::bytearray(buf, len));
    }
private:
    PyCallback m_pyfn;
};

PYBIND11_MODULE(haha, m) {
    pybind11::class_<Haha>(m, "Haha")
        .def("setCallback", &Haha::setCallback);
}

// python
def fn(data):
    print(data)

hahaInstance = m.Haha()
hahaInstance .setCallback(fn)
while True:
    // block to make sure hahaInstance is always running, then callback will print data
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70603855

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档