免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2738 | 回复: 0
打印 上一主题 下一主题

使用 Boost.Python 嵌入 Python 模块到 C++ [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-09-05 11:08 |只看该作者 |倒序浏览
使用 Boost.Python 嵌入 Python 模块到 C++
Boost.Python 目前并没有提供完整的将 Python 模块嵌入到 C++ 的包装库,
因此许多工作我们还必须通过 Python C API 来进行。 但是, 利用 Boost.Python
中提供的一些模块, 能够给我们的工作带来极大便利。
1 修改模块加载路径,装入 Python 模块
与任何一个其它 Python 嵌入 C/C++ 的程序一样, 我们需要在第一条 #include
语句处含入 Python.h, 并在程序开始时调用 Py_Initialize(),
在程序结束时调用 Py_Finalize()。
接下来, 我们便可以开始准备装入 Python 模块了。 为了让 Python 解释器能够正确地找到
Python 模块所在的位置, 我们需要将 Python 模块所在的路径添加到模块搜索路径中,
添加搜索路径的 Python 语句如下:
[color="#a020f0"]import sys
[color="#a52a2a"]if [color="#a52a2a"]not '[color="#ff00ff"]/module/path' [color="#a52a2a"]in sys.path:
    sys.path.append('[color="#ff00ff"]/module/path')
我们使用 Python C API 执行类似的语句, 就能将模块的搜索路径添加到 Python
解释器中。 添加了搜索路径后, 就可以通过 PyImport_ImportModule
函数加载 Python 模块了。 PyImport_ImportModule 返回值是
PyObject *, 为了避免手工处理繁琐的引用计数等问题,
我们求助于 Boost.Python 提供的 handle 模块, 将 PyObject *
封装起来, 以方便使用, 代码如下:
[color="#a020f0"]#include [color="#ff00ff"]
...
    boost::python::handle* _module; [color="#0000ff"]// Module handle.
    std::string path; [color="#0000ff"]// Path of the Python module.
    std::string module; [color="#0000ff"]// Module name.
...
    [color="#a52a2a"]try
    {
        PyRun_SimpleString([color="#ff00ff"]"import sys");
        PyRun_SimpleString((std::string([color="#ff00ff"]"if not '") + path
            + [color="#ff00ff"]"' in sys.path: sys.path.append('" + path + [color="#ff00ff"]"')").c_str());
        _module = [color="#a52a2a"]new boost::python::handle(
            PyImport_ImportModule(([color="#2e8b57"]char *) module));
        ...
    }
    [color="#a52a2a"]catch (...)
    {
        PyErr_Print();
        PyErr_Clear();
        [color="#a52a2a"]delete _module;
        _module = [color="#ff00ff"]NULL;
        [color="#a52a2a"]return [color="#ff00ff"]false;
    }
...
需要注意的是, 通过 Python C API 加载的 Python 解释器并没有把当前路径列入默认的搜索路径中。
因此, 即使你的 Python 模块就存放在当前路径, 你也必须使用上面的代码将当前路径添加到搜索路径中之后,
才能通过 PyImport_ImportModule 加载到模块。
当 Python 模块使用完毕或程序结束时, 请使用 delete 将
_module 指针释放, handle 被释放的时候会自动释放相应的
Python 模块并回收相应资源。
2 调用 Python 函数
导入了 Python 模块之后, 调用 Python 函数就非常容易了。 Boost.Python
里封装了一个非常好用的模板函数 boost::python::call_method,
它可以替你处理调用函数时需要处理的种种细节, 将你从 Python C API 中繁琐的“将参数打包为
PyObject *”、 “构造 Tuple”、 “传递 Tuple”、
“解包返回值”等工作中彻底解放出来, 你只需要这样:
    boost::python::call_method(模块指针, [color="#ff00ff"]"Python 函数名",
        参数 [color="#ff00ff"]1, 参数 [color="#ff00ff"]2, ...);
模块指针可以通过我们前面得到的 _module 的 get
方法获得, 例如:
...
    [color="#2e8b57"]bool result;
    std::string config_file;
    ...
    [color="#a52a2a"]try
    {
        [color="#a52a2a"]return boost::python::call_method(_module->get(), [color="#ff00ff"]"initialize",
            config_file);
    }
    [color="#a52a2a"]catch (...)
    {
        PyErr_Print();
        PyErr_Clear();
        ...
    }
...
3 使用 Python 类对象
使用 Python C API 调用 Python 函数和调用 Python 类对象是没有太大区别的,
我们只需要调用类的构造方法, 得到一个类对象, 然后把该类的指针看做模块指针,
按照前面调用普通函数的方法调用类成员方法就可以了。 例如, 下列代码从
_module 中创建了一个 YukiSession 对象, 然后调用了其中的
on_welcome 方法。 除了展示调用类成员方法外, 这段代码还展示了构造
Python list 对象、 从 Python list 对象中获取元素的方式。
    ...
    boost::python::handle _yukisession;
    ...
    [color="#0000ff"]// Retrieve the module handle and namespace handle.
    boost::python::object main_module(*_module);
    boost::python::object main_namespace = main_module.attr([color="#ff00ff"]"__dict__");
    [color="#0000ff"]// Call the method and get the object handle.
    _yukisession = boost::python::handle((PyRun_String(
        [color="#ff00ff"]"YukiSession()", Py_eval_input,
        main_namespace.ptr(), main_namespace.ptr())));
    ...
    [color="#0000ff"]// Compose a list.
    boost::python::list param;
    param.append(boost::python::str(_addr.get_host_addr()));
    param.append(boost::python::str());
    [color="#0000ff"]// Call the method and retrieve the result.
    [color="#0000ff"]// Method is equivalent to:
    [color="#0000ff"]// "bool __thiscall YukiSession::on_welcome(list param);"
    result = boost::python::call_method
        (_yukisession.get(), [color="#ff00ff"]"on_welcome", param);
    [color="#0000ff"]// Extract an item from a list.
    str = boost::python::call_method
        (param.ptr(), [color="#ff00ff"]"__getitem__", [color="#ff00ff"]1);
    ...
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/18816/showart_165183.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP