如何在Python中将“managedbuffer”转换为可调用的

2024-06-01 03:07:35 发布

您现在位置:Python中文网/ 问答频道 /正文

我用SWIG编写了一个用于C++ 14库的Python包装器。 在C++ API中,我可以登记STD::函数作为回调。在

我有一个std::function的SWIG类型映射来传递lambda表达式 调用Python回调:

%typemap(in) std::function {
    auto callback = [$input](auto&&... params) {
       PyGILState_STATE state = PyGILState_Ensure();

       PyObject* result =  PyObject_CallFunctionObjArgs($input,makePyObject(std::forward<decltype(params)>(params))..., NULL);
       const int retVal = PyObject_IsTrue(result);

       Py_DECREF(result);
       PyGILState_Release(state);
       return retVal == 1;
   };
   $1 = std::move(callback);
}

当我运行一个测试脚本时,下面的Python表达式可以工作 罚款:

^{pr2}$

但是,此表达式不起作用:

self.cppInterface.registerFunc(lambda a,b: self.doStuff)

当我把lambda直接传递给寄存器函数时, 当从C++调用回调时,我得到以下错误:

TypeError: 'managedbuffer' object is not callable

为什么PyObject$input不可调用? 如何允许这两个Python表达式?在

示例代码:

https://github.com/nullmedium/python-swig-demo


Tags: lambda函数autoinput表达式callbackfunctionparams
1条回答
网友
1楼 · 发布于 2024-06-01 03:07:35

看来你有参考计数问题。您需要保留对$input的引用,即使在std::function类型映射完成之后也是如此。否则,一旦对registerFunc的调用完成,它将丢失一个引用。最简单的方法是让您的类型映射捕获std::shared_ptr,而不是原始的PyObject,例如:

%typemap(in) std::function {
    Py_INCREF($input);
    static const auto decref = [](PyObject *o) {
        Py_DECREF(o); // This needs to be another lambda/function because Py_DECREF is really a macro
    };
    std::shared_ptr<PyObject> callable($input, decref);
    auto callback = [callable](auto&&... params) {
       PyGILState_STATE state = PyGILState_Ensure();
                                                      // Back to raw PyObject    
       PyObject* result =  PyObject_CallFunctionObjArgs(callable.get(),makePyObject(std::forward<decltype(params)>(params))..., NULL);
       int retVal = -1;

       if (result)
       {
           retVal = PyObject_IsTrue(result);
           Py_DECREF(result);
       }

       PyGILState_Release(state);
       return retVal == 1;
   };
   $1 = std::move(callback);
}

理想情况下,我应该使用std::unique_ptr,但即使使用generalised lambda captures来阻止复制构造,并迫使SWIG不需要生成代码,也需要做更多的工作。在

我可能会在类型映射中至少抛出一个PyCallable_Check,以便更好地度量。在

相关问题 更多 >