在Python中暴露C++函数并在C++中嵌入Python

6 投票
3 回答
3486 浏览
提问于 2025-04-17 11:55

我的应用程序有一些事件,每个事件可以有一些动作。这些动作是用C++实现的。我想把这些核心功能暴露给Python,让Python来编写这些动作。这样做的好处是我可以在不重新编译的情况下修改动作。例如:

CppClass o;

// --- this is a action----
o.f1();
o.f2();
// ------------------------

用Python来编写动作脚本:

def action1(o):
    o.f1()
    o.f2()

在C++中,使用解释器来运行这个脚本,找到action1并用一个从C++对象转换过来的PyObject来调用它。实际上,我并没有把f1()和f2()暴露给Python,我只是用Python重新组织了动作的定义,所有的功能都是通过C++的二进制代码来运行的。注意,我不需要在Python中给f1()和f2()提供定义。

现在的问题是:我该如何暴露全局函数呢?比如:

def action2():
    gf1()
    gf2()

boost::python可以暴露函数,但它有点不同,它需要编译一个DLL文件,并且main()属于Python脚本。当然,我可以把全局函数做成类的静态成员,但我只是想知道一下。注意,我必须在Python中给gf1()和gf2()提供定义。

Jython可以很简单地做到这一点:只需在Python代码中导入Xxx,然后调用Xxx.gf1()就可以了。但是在Cython中,我该如何在Python中定义gf1()呢?这是一种扩展,但扩展要求Xxx提前编译。看起来唯一的办法就是把gf()放进一个类里?

3 个回答

1

ffpython是一个C++库,它封装了Python 2.x的接口。查看代码库

调用Python函数的方法是:ffpython.call("fftest", "test_stl", a1, a2, a3);

注册C++类:

ffpython.reg_class<foo_t, PYCTOR(int)>("foo_t")
        .reg(&foo_t::get_value, "get_value")
        .reg(&foo_t::set_value, "set_value")
        .reg(&foo_t::test_stl, "test_stl")
        .reg_property(&foo_t::m_value, "m_value");
1

你可能还想看看 Cython

Cython的主要功能是把(部分)Python代码转换成C或C++代码,从而构建原生的Python扩展。这意味着你可以用一种简洁且类似Python的语法来和C/C++代码进行交互。

Cython的用户指南提供了一个很好的例子,展示了如何从Python调用一个简单的C++类:http://docs.cython.org/src/userguide/wrapping_CPlusPlus.html#declaring-a-c-class-interface

除了创建扩展,Cython还可以生成嵌入Python解释器的C/C++代码,这样你就不需要构建和分发一个外部的DLL。详细信息请查看:http://wiki.cython.org/EmbeddingCython

7

解决了。boost::python的文档真的是很差劲……

举个例子:暴露函数

void ff(int x, int y)
{
    std::cout<<x<<" "<<y<<std::endl;
}

给Python用:

import hello
def foo(x, y)
    hello.ff(x, y)

你需要把它作为一个模块暴露出来:

BOOST_PYTHON_MODULE(hello)
{
    boost::python::def("ff", ff, boost::python::arg("x"), boost::python::arg("y"));
}

但这仍然不是一个“全局函数”,所以要把它暴露到Python的主作用域:

BOOST_PYTHON_MODULE(__main__)
{
    boost::python::def("ff", ff, boost::python::arg("x"), boost::python::arg("y"));
}

然后你就可以写:

def foo(x, y)
   ff(x, y)

撰写回答