http://edyfox.codecarver.org/html/boost_python.html

Boost.Python 是 Boost 中的一个组件,使用它能够大大简化用 C++ 为 Python 写扩展库的步骤,提高开发效率,虽然目前它对 Python 嵌入 C++ 的支持还不是很多,但也能提供很大方便。另外,华宇煜也编写了一份关于Boost.Python 简明教程

1 Boost 安装简介

在正式开始使用 Boost.Python 之前,我们必须先编译 Boost。首先到 Boost 的官方站点 下载 Boost 的源码包,把它们解压到你喜欢的目录,为编译做好准备。另外,在正式安装 Boost.Python 之前,我们必须先正确安装 Python。

1.1 Linux 下的编译

首先切换到 Boost 源码所在的路径,执行 ./configure 脚本,为配置脚本提供 Python 运行环境相应的参数:

./configure --with-python=/usr/bin/python \
            --with-python-version=2.4 \
            --with-python-root=/usr

然后,和绝大部分 Linux 程序一行,执行 make 就可以开始编译了。编译完毕后,切换到 root 权限后再执行make install,把 Boost 相应的头文件和库文件复制到相应的地方,就可以使用了。

1.2 使用 MinGW + MSys 在 Windows 下的编译

首先需要编译的是 Boost 的编译工具 bjam,直接到 bjam 所在目录下,即 Boost 源码包所在目录下的\tools\build\jam_src,执行 build.bat mingw,稍等片刻,bjam.exe 就编译好了。把编译好的 bjam.exe 复制到你的%PATH% 路径能够直接找到的地方,为后续的编译工作做好准备。

接下来,切换到 Boost 源码所在路径,执行 bjam 进行编译。我们需要提供关于 Python 的一些参数,变量 PYTHON_ROOT 指向 Python 运行环境所在的目录,变量 PYTHON_VERSION 的值为 Python 的版本号,如果你的 Python 安装路径与滇狐不同,请将相应的变量修改为你机器上相应的路径,编译命令行如下:

bjam.exe "-sTOOLS=mingw" "-sPYTHON_ROOT=E:\Python" "-sPYTHON_VERSION=2.4"

编译完毕后,你将会在你的 C:\Boost 下找到编译得到的 Boost 相应头文件与库文件,你可以根据你的需要将它移动到别的地方备用。

2 使用 Boost.Python 嵌入 Python 模块到 C++

Boost.Python 目前并没有提供完整的将 Python 模块嵌入到 C++ 的包装库,因此许多工作我们还必须通过 Python C API 来进行。但是,利用 Boost.Python 中提供的一些模块,能够给我们的工作带来极大便利。

2.1 修改模块加载路径,装入 Python 模块

与任何一个其它 Python 嵌入 C/C++ 的程序一样,我们需要在第一条 #include 语句处含入 Python.h,并在程序开始时调用 Py_Initialize(),在程序结束时调用 Py_Finalize()

接下来,我们便可以开始准备装入 Python 模块了。为了让 Python 解释器能够正确地找到 Python 模块所在的位置,我们需要将 Python 模块所在的路径添加到模块搜索路径中,添加搜索路径的 Python 语句如下:

import sys
if not '/module/path' in sys.path:
    sys.path.append('/module/path')

我们使用 Python C API 执行类似的语句,就能将模块的搜索路径添加到 Python 解释器中。添加了搜索路径后,就可以通过PyImport_ImportModule 函数加载 Python 模块了。PyImport_ImportModule 返回值是 PyObject *,为了避免手工处理繁琐的引用计数等问题,我们求助于 Boost.Python 提供的 handle 模块,将 PyObject * 封装起来,以方便使用,代码如下:

#include <boost/python.hpp>

...

boost::python::handle<>* _module; // Module handle.
    std::string path; // Path of the Python module.
    std::string module; // Module name.

...

try
    {
        PyRun_SimpleString("import sys");
        PyRun_SimpleString((std::string("if not '") + path
            + "' in sys.path: sys.path.append('" + path + "')").c_str());
        _module = new boost::python::handle<>(
            PyImport_ImportModule((char *) module));
        ...
    }
    catch (...)
    {
        PyErr_Print();
        PyErr_Clear();
        delete _module;
        _module = NULL;
        return false;
    }

...

需要注意的是,通过 Python C API 加载的 Python 解释器并没有把当前路径列入默认的搜索路径中。因此,即使你的 Python 模块就存放在当前路径,你也必须使用上面的代码将当前路径添加到搜索路径中之后,才能通过 PyImport_ImportModule 加载到模块。

当 Python 模块使用完毕或程序结束时,请使用 delete 将 _module 指针释放,handle 被释放的时候会自动释放相应的 Python 模块并回收相应资源。

2.2 调用 Python 函数

导入了 Python 模块之后,调用 Python 函数就非常容易了。Boost.Python 里封装了一个非常好用的模板函数boost::python::call_method,它可以替你处理调用函数时需要处理的种种细节,将你从 Python C API 中繁琐的“将参数打包为 PyObject *”、“构造 Tuple”、“传递 Tuple”、“解包返回值”等工作中彻底解放出来,你只需要这样:

    boost::python::call_method<返回值类型>(模块指针, "Python 函数名",
        参数 1, 参数 2, ...);

模块指针可以通过我们前面得到的 _module 的 get 方法获得,例如:

...
    bool result;
    std::string config_file;

...

try
    {
        return boost::python::call_method<bool>(_module->get(), "initialize",
            config_file);
    }
    catch (...)
    {
        PyErr_Print();
        PyErr_Clear();
        ...
    }

...

2.3 使用 Python 类对象

使用 Python C API 调用 Python 函数和调用 Python 类对象是没有太大区别的,我们只需要调用类的构造方法,得到一个类对象,然后把该类的指针看做模块指针,按照前面调用普通函数的方法调用类成员方法就可以了。例如,下列代码从 _module 中创建了一个 YukiSession 对象,然后调用了其中的 on_welcome 方法。除了展示调用类成员方法外,这段代码还展示了构造 Python list 对象、从 Python list 对象中获取元素的方式。

    ...

boost::python::handle<> _yukisession;

...

// Retrieve the module handle and namespace handle.
    boost::python::object main_module(*_module);
    boost::python::object main_namespace = main_module.attr("__dict__");

// Call the method and get the object handle.
    _yukisession = boost::python::handle<>((PyRun_String(
        "YukiSession()", Py_eval_input,
        main_namespace.ptr(), main_namespace.ptr())));
    ...

// Compose a list.
    boost::python::list param;
    param.append(boost::python::str(_addr.get_host_addr()));
    param.append(boost::python::str());

// Call the method and retrieve the result.
    // Method is equivalent to:
    // "bool __thiscall YukiSession::on_welcome(list param);"
    result = boost::python::call_method<bool>
        (_yukisession.get(), "on_welcome", param);
    // Extract an item from a list.
    str = boost::python::call_method<std::string>
        (param.ptr(), "__getitem__", 1);

...

3 在嵌入的 Python 模块中调用 C++ 程序

通过动态链接库的方式使用 Boost.Python 导出C++ 模块到 Python 程序与在 C++ 可执行程序中导出模块给嵌入的 Python 解释器,编写程序的方式几乎是完全相同的。因此这里只简单介绍导出普通函数的方法,想详细了解更多高级功能,如导出 C++ 类、导出可被 Python 重载的类等,可以参看华宇煜的Boost.Python 简明教程或官方Boost.Python 文档。

3.1 导出 C++ 函数

首先使用 BOOST_PYTHON_MODULE 宏定义需要导出给 Python 的模块,然后用 boost::python::def 语句定义导出的函数、参数列表以及 Doc String,例如在下面的例子中,我们导出了一个 C++ 函数 yukigettext,并重命名为 gettext

const char *yukigettext(const char *id);

BOOST_PYTHON_MODULE(yuki)
{
    boost::python::def("gettext", yukigettext,
        boost::python::args("id"), "Translate message.");
}

3.2 为 Python 初始化 C++ 模块

使用 BOOST_PYTHON_MODULE(name) 定义了 Python 模块后,该宏会自动生成一个函数 initname,我们需要在Py_Initialize() 之后调用这个自动生成的函数,初始化导出到 Python 的模块。例如我们刚才导出模块用的宏BOOST_PYTHON_MODULE(yuki),因此初始化的时候就应该调用 inityuki()

...
    Py_Initialize();
    inityuki();
...

3.3 在 Python 模块中调用 C++ 模块

此时我们在 Python 模块中只需要像普通的 Python 模块那样,将导入的 C++ 模块用 import 语句加载进来,就可以调用了:

import yuki

...

print yuki.gettext("This is a test!")

【转】Boost.Python的更多相关文章

  1. boost.python笔记

    boost.python笔记 标签: boost.python,python, C++ 简介 Boost.python是什么? 它是boost库的一部分,随boost一起安装,用来实现C++和Pyth ...

  2. Boost.Python简介

    Boost.Python简单概括:是Boost库的一部分:用来在C++代码中调用python代码以及在Python代码中调用C++代码,并且避免用户直接操作指针. 以下内容搬运自:https://wi ...

  3. 编译boost python模块遇到的错误:../../libraries/boost_1_44_0/boost/python/detail/wrap_python.hpp:75:24: fatal error: patchlevel.h: No such file or directory

    就是遇到类似标题上面的错误. 原因是没有安装对应python的python-dev依赖,不然编译到boost python模块的时候就会出错. 所以解决方案是sudo apt-get install ...

  4. Boost.Python:使用继承

    An example #include <boost/python.hpp> #include <memory> #include <iostream> using ...

  5. 64位win7下安装Boost 1.59.0 + boost.python 1.59.0 + gccxml + pygccxml + pyplusplus(py++)

    由于安装过程中实在是出现了N多问题,所以不得不专门写个帖子来记录一下这破东西在Win7下的安装过程,避免以后还要再用的时候踩坑. 1.Boost简介 Boost库是一个可移植.提供源代码的C++库,作 ...

  6. 使用boost.python封装C++库

    使用boost.python封装C++库 C++以高性能著称,但是编写较为复杂.而简洁是Python的强项.如果能珠联璧合,就能发挥两家之长.本文尝试用boost库的python模块封装C++ 前期准 ...

  7. Win7 VS2017 Boost Python入门

    闲来无事想练习下用Python作为游戏脚本绑定到C++,网上搜了下,Python文档有些例子,但是太过复杂,gayhub无意中看到有人用Boost Python绑定,简单粗暴,省时省力,记录备忘. 写 ...

  8. C++ boost.python折腾笔记

    为了让当年研究生时写的图像处理系统重出江湖起到更大的作用,应研究生导师的意见,对原有的c++框架做了python扩展处理,为了避免遗忘,备注如下: 一.boost 编译 下载boost源码,这里使用b ...

  9. boost.python入门教程 ----python 嵌入c++

    Python语言简介 Python是一种脚本语言.以开放的开发接口和独特的语法著称.尽管Python在国内引起注意只有几年的时间,但实际上Python出现于上世纪90年代(据www.python.or ...

  10. 【转】利用Boost.Python将C++代码封装为Python模块

    用Boost.Python将C++代码封装为Python模块 一.     基础篇 借助Boost.Python库可以将C/C++代码方便.快捷地移植到python模块当中,实现对python模块的扩 ...

随机推荐

  1. LocationOnScreen-控件在手机屏幕中的位置坐标

    我们可以通过如下的方法获得某个控件在屏幕中的绝对坐标 代码如下: private int[] mHistoryDisplayButtonLocation; private int mHistoryDi ...

  2. ASP.NET MVC案例教程(基于ASP.NET MVC beta)——第四篇:传递表单数据

    摘要      本文将完成我们“MVC公告发布系统”的公告发布功能,以此展示在ASP.NET MVC中如何传递处理表单的数据. 前言      通过前几篇文章,我们已经能比较自如的使用ASP.NET ...

  3. 机器学习分支:active learning、incremental learning、online machine learning

    1. active learning Active learning 是一种特殊形式的半监督机器学习方法,该方法允许交互式地询问用户(或者其他形式的信息源 information source)以获取 ...

  4. 使用 STL 辅助解决算法问题

    不要重复制造轮子,而且你造的轮子未必比得上别人的: <numeric>⇒ accumulate,累积容器中区间的和,可以指定初值: 为什么 STL 中的容器和算法一定关于区间的操作一定是左 ...

  5. HDU 1556 Color the ball【算法的优化】

    /* 解题思路:每次仅仅求解一開始的第一个数字,让第一个数字加一,最后的一个数字的后面一个数减一.我们能够想想,最后加的时候,就是加上前面一个数出现的次数和自己本身出现的次数. 解题人:lingnic ...

  6. 10.5 android输入系统_Reader线程_使用EventHub读取事件和核心类及配置文件_实验_分析

    4. Reader线程_使用EventHub读取事件 使用inotify监测/dev/input下文件的创建和删除 使用epoll监测有无数据上报 细节: a.fd1 = inotify_init(& ...

  7. 【例题 6-6 UVA - 679】Dropping Balls

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 直接模拟会超时. 根据奇偶的规律.直接判断会往哪里走就好. 每个二叉树的节点.必然是左边和右边走的次数对半分.->奇数左边多一 ...

  8. 推荐一下《聊聊JVM》的专栏

    依照惯例新开了一个专栏后要单推一下.推荐一下<聊聊JVM的专栏>,网上关于JVM的文章太多,这个专栏希望能在已有的资料的基础上写出点新意,对一些重要的概念归纳总结,说说自己的观点.理解和实 ...

  9. Java反射学习总结四(动态代理使用实例和内部原理解析)

    通过上一篇文章介绍的静态代理Java反射学习总结三(静态代理)中,大家可以发现在静态代理中每一个代理类只能为一个接口服务,这样一来必然会产生过多的代理,而且对于每个实例,如果需要添加不同代理就要去添加 ...

  10. 一个例子讲解wav头文件 stm32声音程序 录音和播放 wav

    下面我们一wav头文件来分析一下: 下面是双声道的,16位,48000采样录的wav文件: 打开属性,能看到的有用信息只有比特率了: 上图的比特率就是 wav头文件里的bitrate: 1536kbp ...