我有一个用C ++编写的内部库,我正在努力扩展到Python。我开始考虑使用Boost.Python来完成这项任务,但我愿意接受替代方案。
目前我有一个需要接受Python类实例的C ++函数,然后使用该对象的方法来执行某些任务。这个想法是让Python用户永远不需要处理C ++。他们应该从我将提供的Python模板/示例类创建这个Python对象,使用预设的方法名称,我可以假设它在我的C ++库中。
暴露给Python用户的界面如下所示:
class Foo(object):
def __init__(self, args):
"""create an instance of this class with instance-specific attributes"""
def Bar1(self, a, b, c):
"""do something with the given integers a, b and c"""
pass
def Bar2(self, a, b, c):
"""do something else with the given integers a, b and c"""
pass
import mylib
cheese = mylib.Wine()
cheese.do_something(Foo)
在C ++中,相应的代码如下所示:
#include <boost/python.h>
#include <Python.h>
class Wine {
public:
Wine() {};
~Wine() {};
static void do_something(boost::python::object *Foo) {
int a = 1;
int b = 2;
int c = 3;
Foo->attr("Bar1")(a, b, c);
Foo->attr("Bar2")(a, b, c);
};
};
BOOST_PYTHON_MODULE(mylib)
{
using namespace boost::python;
class_<Wine>("Wine")
.def("do_something", &Wine::do_something);
};
我已经成功编译了这段代码并验证了名为Wine的C ++类实际上是暴露给Python的,我可以访问它的成员函数。如果我写一个名为“greet()”的成员函数只返回“Hello,world!”,它就能完美运行。
我需要强调传递Foo实例的重要性。我没有什么可以简单地将Foo模块导入C ++代码并在C ++中创建Foo实例。我想从Python用户接收的对象具有我需要使用的特定于实例的属性,而不是类本身。
问题是我无法弄清楚如何将Python实例传递给do_something,因此它将作为可调用的boost :: python :: object出现在C ++中。上面的代码返回以下C ++签名不匹配错误:
Boost.Python.ArgumentError: Python argument types in
Wine.do_something(Wine, Foo)
did not match C++ signature:
do_something(boost::python::api::object*)
在网上浏览答案两天没有取得任何进展。似乎有很多关于如何将C ++类传递给Python的信息,但我无法找到相反方向的信息。非常感谢这里的一些指导。
谢谢!
答案 0 :(得分:3)
初始代码中有两个错误:
self
和一个Foo
实例)传递给只接受一个参数的静态Wine::do_something()
C ++函数。要解决此问题,在公开Wine
类时,需要通过boost::python::class_::staticmethod()
成员函数将Python Wine.do_something()
成员函数设置为静态。当作为静态方法公开时,Boost.Python将不再传递self
实例参数。PyObject*
),Boost.Python提供了更高级别的表示法boost::python::object
,它通常按值传递或参考。在内部,此类与boost::python::handle
交互,为PyObject
执行智能指针管理。这是一个基于原始代码的完整Python扩展:
#include <boost/python.hpp>
class Wine
{
public:
static void do_something(boost::python::object object)
{
int a = 1;
int b = 2;
int c = 3;
object.attr("Bar1")(a, b, c);
object.attr("Bar2")(a, b, c);
};
};
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
python::class_<Wine>("Wine")
.def("do_something", &Wine::do_something)
.staticmethod("do_something")
;
};
交互式使用:
>>> class Foo(object):
... def Bar1(self, a, b, c):
... print "Bar1", locals()
... def Bar2(self, a, b, c):
... print "Bar2", locals()
...
>>> import example
>>> cheese = example.Wine()
>>> cheese.do_something(Foo())
Bar1 {'a': 1, 'c': 3, 'b': 2, 'self': <__main__.Foo object at 0xb6b0f2ac>}
Bar2 {'a': 1, 'c': 3, 'b': 2, 'self': <__main__.Foo object at 0xb6b0f2ac>}
答案 1 :(得分:0)
要公开接受Python对象作为参数的方法,您应该使用boost::python::object
而不是boost::python::object *
void do_something(boost::python::object Foo)
要公开静态方法,请将其公开为常规函数:def("do_something", Wine::do_something);
import mylib
# method
cheese = mylib.Wine()
foo = Foo()
cheese.do_something(foo)
#static method
foo = Foo()
mylib.do_something(foo)