Boost.Python 是怎么工作的?
Python是怎么调用C++对象的呢?虽然Python的解释器是用C语言写的,而且是用C语言的编译器编译的,但它依然可以和C++对象进行互动。
3 个回答
C++可以通过使用extern "C"声明来和C语言进行互操作,也就是说,C++程序可以调用C语言写的代码,反之亦然。
Python有一个C语言的接口(可以查看 http://docs.python.org/2/c-api/ 或 http://docs.python.org/3/c-api/)。这个接口定义了一种通用的对象类型,叫做 PyObject
,其实就是一个普通的C结构体。这个结构体几乎定义了Python对象能做的所有事情,比如说在这个对象上进行加法或比较操作,或者像调用函数一样去调用它。
因为Python的类型也是对象(所以在C中用 PyObject
结构来表示),所以定义一个新类型其实很简单,只需要定义一个新的 PyObject
结构体就可以了。当在Python中调用方法时,解释器会把这个调用转发给和这个结构体相关联的C函数。
只要一个编译好的扩展提供了正确的入口点,让Python解释器能够查看它并找到可用的内容(上面提到的文档详细解释了这一点),那么你就可以像使用其他普通对象一样使用这些对象——顺便说一下,这些对象也是用同样的C接口构建的。只需要用 import
导入这个编译好的扩展就可以了。
我希望上面的内容能让你大致明白Python解释器是如何从编译扩展中调用东西的。唯一缺少的部分是C接口是如何调用C++代码的。
Boost.Python通过在代码中声明C入口点来实现这一点,具体方法可以参考这里的解释: 优雅地从C调用C++。每次你调用,比如说 boost::python::class_
,它都会为你在Python中声明的类型执行这个操作,从而创建一个 PyObject
,这个对象代表你的类,并且使用你选择的名称。当你在这个类上调用 .def
时,你就开始填充这个结构体的内部槽位,声明更多的方法、运算符和属性。每个内部槽位都指向一个C风格的函数,这个函数实际上只是对等价的C++调用的一个封装。
Boost.Python 有一些特别的宏,用来声明函数,使用 extern "C"
这样写是为了让 Python 解释器能够调用这些函数。这个过程有点复杂,不过你可以查看 Boost 的文档,里面有更多的信息。