将Python类实例传递给C ++函数

Alp*_*ner 5 boost-python

我有一个用C ++编写的内部库,目前正在研究将其扩展到Python中。我在开始时就考虑了Boost.Python,但是我愿意接受其他选择。

当前,我有一个C ++函数,需要接受一个Python类实例,然后使用该对象的方法执行某些任务。这个想法是让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)
Run Code Online (Sandbox Code Playgroud)

在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);
};
Run Code Online (Sandbox Code Playgroud)

我已经成功地编译了此代码,并验证了名为Wine的C ++类确实适用于Python,并且可以访问其成员函数。如果我编写了一个成员函数“ greet()”,该成员函数仅返回“ Hello,world!”,那么它将很好地工作。

我在这里需要强调传递Foo实例的重要性。我没有办法简单地将Foo模块导入C ++代码并在C ++中创建Foo实例。我要从Python用户接收的对象具有我需要使用的属性,该属性特定于实例,而不是类本身。

问题是我无法弄清楚如何将Python实例传递到do_something中,以使其在C ++中作为可调用的boost :: python :: object出现。上面的代码返回以下C ++签名不匹配错误:

Boost.Python.ArgumentError: Python argument types in
    Wine.do_something(Wine, Foo)
did not match C++ signature:
    do_something(boost::python::api::object*)
Run Code Online (Sandbox Code Playgroud)

仔细阅读互联网的答案两天没有取得任何进展。关于如何将C ++类传递到Python中似乎有很多信息,但是我找不到相反方向的信息。非常感谢您在这里提供一些指导。

谢谢!

Tan*_*ury 5

初始代码有两个错误:

  • Boost.Python 试图将两个参数(self和 的一个实例Foo)传递给Wine::do_something()只接受一个参数的静态C++ 函数。为了解决这个问题,在暴露Wine类时,Wine.do_something()需要通过boost::python::class_::staticmethod()成员函数将 Python成员函数设置为静态。当作为静态方法公开时,Boost.Python 将不再传递self实例参数。
  • 与 Python/C API 中指针通常用作对象句柄 ( 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")
    ;
};
Run Code Online (Sandbox Code Playgroud)

互动使用:

>>> 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>}
Run Code Online (Sandbox Code Playgroud)