我正在尝试在Python
中为pika
编写一个包装C++
类。在pika
中,当消息被消费时,有一个名为callback(ch, method, properties, body)
的函数。要使用消息,您必须将callback
函数放在basic_consume
方法中。在我的例子中,我的callback
函数驻留在C++
代码中,因为C++
处理所有必要的事情,然后将回调转移回Consumer类。我想在C++
文件中执行每个逻辑,并在这种情况下单独留下Python class
。
C++:
#include <stdio.h>
#include <boost/python.hpp>
#include <boost/function.hpp>
using namespace std;
using namespace boost::python;
// boost function
void function(object *ch, object *method, object *properties, string body) {
cout << "INSIDE FUNC" << body << endl;
}
int main() {
Py_Initialize();
try {
boost::function<void(object*, object*, object*, string)> myfunc;
myfunc = boost::bind(function, _1, _2, _3, _4);
object a = import("consumer");
object b = a.attr("A");
object c = b.attr("callback")(boost::ref(myfunc));
}
catch(error_already_set const &) {
PyErr_Print();
}
return 0;
}
Python: consumer.py
import pika
class A:
def __init__(self):
cppcallback = None
self.connect()
def connect():
connection = pika.BlockingConnection(pika.ConnectionParameters("localhost"))
channel = connection.channel()
def callback(cppdosomething):
print "CALLED"
cppcallback = cppdosomething
self.start_consume()
def start_consume(self):
channel.basic_consume(cppcallback, queue="hello_world")
channel.start_consuming()
但是现在,我收到了这个错误。
TypeError:没有为C ++类注册的Python类boost :: function&lt; void(boost :: python :: api :: object *,boost :: python :: api :: object *,boost :: python :: api :: object *,std :: string)&gt;
感谢任何帮助。
答案 0 :(得分:1)
您的示例代码存在一些无关的问题:
object b = a.attr("A");
- 获取类类型。您需要运行构造函数来创建A
的实例。这意味着a.attr("A")();
。cppcallback
是__init__
和callback
函数中的局部变量。在start_consume
中它未定义。这应该是一个成员变量,如self.cppcallback
。object
作为回调处理程序的参数是值得商榷的。我认为按价值传递它们很好。我写了一个简化的脚本,模仿你所拥有的:
class A:
def __init__(self):
self.handler = None
def callback(self, handler):
self.handler = handler
self.do_something()
def do_something(self):
self.handler(1,2,3,"foo")
这种方法非常简单。
首先使用object
创建一个可调用的make_function
。
然后从我们的脚本,test_module
的构造和实例中导入Python A
并调用它的callback
成员将其作为参数传递给我们的可调用对象。
#include <boost/python.hpp>
namespace bp = boost::python;
void callback_handler(bp::object ch
, bp::object method
, bp::object properties
, std::string const& body)
{
std::cout << "in handler: " << body << std::endl;
}
int main()
{
Py_Initialize();
try {
bp::object h = bp::make_function(callback_handler);
bp::object a = bp::import("test_module");
bp::object b = a.attr("A")(); // Construct instance of A
b.attr("callback")(h);
} catch (bp::error_already_set const &) {
PyErr_Print();
}
return 0;
}
控制台输出:
>example_1.exe
in handler: foo
boost::function
使用boost::function
对象作为回调处理程序有点棘手,因为默认情况下boost::function
不支持boost::python
。因此,我们首先需要启用对boost::function
的支持,如this answer Tanner Sansbury中所述。
NB :此片段需要先包括boost/python.hpp
!
// ============================================================================
// Enable support for boost::function
// See https://stackoverflow.com/a/18648366/3962537
// ----------------------------------------------------------------------------
#include <boost/function.hpp>
#include <boost/function_types/components.hpp>
// ----------------------------------------------------------------------------
namespace boost { namespace python { namespace detail {
// ----------------------------------------------------------------------------
// get_signature overloads must be declared before including
// boost/python.hpp. The declaration must be visible at the
// point of definition of various Boost.Python templates during
// the first phase of two phase lookup. Boost.Python invokes the
// get_signature function via qualified-id, thus ADL is disabled.
// ----------------------------------------------------------------------------
/// @brief Get the signature of a boost::function.
template <typename Signature>
inline typename boost::function_types::components<Signature>::type
get_signature(boost::function<Signature>&, void* = 0)
{
return typename boost::function_types::components<Signature>::type();
}
// ----------------------------------------------------------------------------
}}} // namespace boost::python::detail
// ============================================================================
其余与第一种情况非常相似。
#include <iostream>
#include <boost/python.hpp>
namespace bp = boost::python;
void callback_handler(bp::object ch
, bp::object method
, bp::object properties
, std::string const& body
, std::string const& extra)
{
std::cout << "in handler: " << body << extra << std::endl;
}
int main()
{
Py_Initialize();
try {
typedef boost::function<void(bp::object, bp::object, bp::object, std::string)> handler_fn;
handler_fn my_handler(boost::bind(callback_handler, _1, _2, _3, _4, " bar"));
bp::object h = bp::make_function(my_handler);
bp::object a = bp::import("test_module");
bp::object b = a.attr("A")();
b.attr("callback")(h);
} catch (bp::error_already_set const &) {
PyErr_Print();
}
return 0;
}
控制台输出:
>example_2.exe
in handler: foo bar