`
rrkn06rrkn
  • 浏览: 12540 次
社区版块
存档分类
最新评论

Python 与 C++ 的交互编程

 
阅读更多

Python 与 C++ 的交互编程
2011年03月28日
  基础知识
  编译语言和解释语言
  尽管现在很多编程技术都在交融,出现了不少带有编译系统的解释语言,和带有复杂运行时系统的编译语言,但通常我们还是可以比较明确的区分它们。在这个大前提下,Python和C++属于这个两类技术中比较极端的代表。
  编译时和运行时
  C++的强大之处在于高效的生成产品和强大复杂的编译系统。利用C++的语法,可以生成非常灵活强大的程序,而这其中大部分工作都是在编译程序的过程中完成。相对而言,C++没有标准的运行时(CLI系统还没有真正成为C++的标准,只能说提供了一个C++在CLI系统上运行的标准),要建立一个完善的运行时,要么就要投入大量的成本,要么就寻找一个合适的运行时环境调用。Python自身是一个成熟完备的脚本语言,拥有开放的编程和扩展接口,加上它本身的对象机制设计非常适合外部调用,Python与编译语言,特别是C/C++的互嵌入日益成为关注焦点。
  互嵌入
  Python有多种实现,比较著名的有C语言编写的官方实现,Java版的Jython,.net版的IronPython,值得一提的是,后两者都是由 Jim Hugunin 开发,此人现在微软主持动态语言研究项目。另外,有一个CPython调用.net的桥接系统 PythonDotNet,由ZOPE社区的一位技术人员开发。现在使用最广泛的互嵌入场合,是C/C++和CPython之间的互嵌入。
  Python 的官方版本本身就是由C语言编写,有开放的C接口。使用C语言调用和扩展Python都非常简单。基于这个前提,使用C++语言与Python进行互操作也并不复杂。现在已经有若干用于Python API封装的C++库,这里我们要讨论的是Boost.Python。这是著名的C++库Boost的重要组成之一。
  用C++扩展Python
  Python扩展入门
  Python允许在遵循一定规则的前提下调用语言和操作系统无关的动态链接库。通常,在Windows下为.dll,而在*nix下为.so文件。操作系统的区别由C++编译器、Boost库和Python解释器屏蔽,最终程序员可以基本忽视其中的区别。
  在实现互嵌入的时候,要考虑Python的运行时限制,Python的虚拟机只能操作Python对象,并且虚拟机拥有自己的内存管理模式,应该根据情况对C++程序和Python环境所交换的信息进行必要的封装和拆封。
  Python本身提供了C语言扩展所需要的接口文件,可以在Python的include,Libs,DLLs目录下找到对应的文件。
  一个纯C语言的Python扩展可能类似下面这样:
  #include static PyObject *spam_system(PyObject *self, PyObject *args){    const char *command;    int sts;    if (!PyArg_ParseTuple(args, "s", &command))        return NULL;    sts = system(command);    return Py_BuildValue("i", sts);}我们根据具体的操作系统和开发工具,把以上函数封装到一个动态链接库中,放入Python的动态链接库搜索路径(Python For Windows中是DLLs)中。就可以把它作为Python的一个模块使用。
  C++封装
  我们知道,C++的代码封装机制和C有所不同,相比真正的纯C语言,C++更为复杂。例如,它有虚函数,有模版,前者使运行时更为复杂和灵活,后者使一些比宏更复杂的语法推导得以实现。Boost.Python为C++程序提供的封装能力,正是基于template。我们要做的,是把C++程序中的函数、类、数据成员等等,都变成Python对象。
  BOOST.Python封装了各平台的Python动态链接库接口,我们要做的只是调用它,封装需要暴露的定义,然后指示编译器生成动态链接库即可。
  函数封装
  Python的API使用回调函数调用Python对象和函数。BOOST提供完整的函数封装过程,一个简单的封装过程如下:
  Hello World
  Following C/C++ tradition, let's start with the "hello, world". A C++ Function:
  char const* greet(){   return "hello, world";}can be exposed to Python by writing a Boost.Python wrapper:
  #include using namespace boost::python;BOOST_PYTHON_MODULE(hello){    def("greet", greet);}That's it. We're done. We can now build this as a shared library. The resulting DLL is now visible to Python. Here's a sample Python session:
  >>> import hello>>> print hello.greet()hello, world
  以上来自BOOST文档。
  面向对象
  对象管理、引用计数
  Python虚拟机提供引用计数和自动垃圾回收能力,但是C++对象没有这样的能力(C++对象运行在Python虚拟机之外)。为了避免程序运行过程中的内存使用问题,需要为函数中传递的指针提供引用计数管理,BOOST通过“调用协议”来支持此功能,详情请见BOOST文档“Call Policies”。
  C++ 对象到 Python 对象的封装
  BOOST文档中提供了C++对象封装至Python对象的方法,主要手段是以class_模板将C++类定义解析为符合C API的形式,一个形如:
  struct World{    void set(std::string msg) { this->msg = msg; }    std::string greet() { return msg; }    std::string msg;};的C++代码可以通过如下方式封装:
  #include using namespace boost::python;BOOST_PYTHON_MODULE(hello){    class_("World")        .def("greet", &World::greet)        .def("set", &World::set)    ;}这里的关键点在于封装代码必有的 BOOST_PYTHON_MODULE 宏和class模板的def。为了支持C++类定义丰富的内容,Boost.Python提供了很多调用方法,比较常用,也比较重要的是构造函数、重载和虚函数的支持。
  构造函数的封装是通过__init__模板封装的,不同的构造函数重载可以通过参数列表区分并重复封装。BOOST文档中给出了这样一个示例:
  class_("World", init())    .def(init())    .def("greet", &World::greet)    .def("set", &World::set);普通函数重载的支持事实上是一种函数封装方法,和这个函数是否是某个类的成员并无关系。基本思路是把不同的函数形式定义为不同的函数指针,然后以普通函数的形式封装。
  虚函数的支持比较复杂,BOOST通过多继承方式支持它,用户需要以多继承定义一个基类的封装,然后暴露这个封装类。在阅读BOOST文档时,要注意封装类在用class_暴露接口时的代码,以下是BOOST文档中的一个示例:
  struct BaseWrap : Base, wrapper{    int f()    {        if (override f = this->get_override("f"))            return f(); // *note*        return Base::f();    }    int default_f() { return this->Base::f(); }};class_("Base")    .def("f", &Base::f, &BaseWrap::default_f)    ;注意封装代码中class_的模板参数是BaseWrap,但def中的第二个函数是&Base::f。def的第三个函数提供函数封装的一些信息,这里指明了该虚函数的默认实现。更多的用法请参考Boost文档。在BOOST中还提供了更复杂的功能,比如可以定义Python类的属性(者甚至比在Python中更简单)。
  在C++程序中嵌入Python
  引用解释器
  Python标准的外部调用方法并不复杂,在Python的文档中可以查到。最简单的调用方式如下:
  #include intmain(int argc, char *argv[]){  Py_Initialize();  PyRun_SimpleString("from time import time,ctime\n"                     "print 'Today is',ctime(time())\n");  Py_Finalize();  return 0;}Py_Initialize();启动虚拟机,Py_Finalize();终止它。PyRun_SimpleString用于执行语句。Boost延续了这一方式,并着眼于将交互过程变得更简单些。BOOST程序中最简单的示例如下:
  Py_Initialize();object main_module((    handle(borrowed(PyImport_AddModule("__main__")))));object main_namespace = main_module.attr("__dict__");handle ignored((PyRun_String(    "hello = file('hello.txt', 'w')\n"    "hello.write('Hello world!')\n"    "hello.close()"  , Py_file_input  , main_namespace.ptr()  , main_namespace.ptr()))); Py_Finalize();从这种复杂度的程序中,体现不出BOOST的优势,它甚至比C程序更复杂。不过这里可以学习一下它的基本框架。也许下面这个更为复杂的示例可以说明些问题:
  object main_module((     handle(borrowed(PyImport_AddModule("__main__")))));object main_namespace = main_module.attr("__dict__");handle ignored((PyRun_String(    "result = 5 ** 2"    , Py_file_input    , main_namespace.ptr()    , main_namespace.ptr())));int five_squared = extract(main_namespace["result"]);我们可以通过这里看到BOOST的一些优势,如通过C++对象(这里main_namespace对象)获取Python数据,并将其转化为C++数据(extract模板)。而下面这个示例演示了BOOST为Python环境提供的C++异常保护:
  try{    object result((handle(PyRun_String(        "5/0"      , Py_eval_input      , main_namespace.ptr()      , main_namespace.ptr()))    ));    // execution will never get here:    int five_divided_by_zero = extract(result);}catch(error_already_set){    // handle the exception in some way}当然,我们也可以选择无异常的版本:
  handle result((allow_null(PyRun_String(    "5/0"   , Py_eval_input   , main_namespace.ptr()   , main_namespace.ptr()))));if (!result)    // Python exception occurredelse    // everything went okay, it's safe to use the result调用脚本
  PyRunString是Python的C-API,Python提供了一系列的调用方法供程序执行脚本使用,也包括了PyRun_File这样的直接调用文件的功能,当然,它不支持C++的I/O,使用的是C风格的文件指针。
  附记
  最后提一下,使用Boost,无论你是要扩展还是嵌入Python,都需要预编译Boost库,编译方法在Boost的文档中也有介绍。使用Boost的时候,要把预编译好的lib链接到link序列中,还要把DLL放到应用程序可以访问到的地方。
分享到:
评论

相关推荐

    python与c++交互样例代码

    ubuntu下实现的在c++程序中调用python脚本的样例程序,可直接编译运行,需安装python-dev,供大家学习参考。修改后可在windows中使用

    python编程

    三个项目,包括简单的 Python 2D 游戏开发,如何利用数据生成交互式的信息图,以及创建和定制简单的 Web 应用,并帮读者解决常见编程问题和困惑。 本书适合对 Python 感兴趣的任何层次的读者阅读。

    C++ 与 Java 混合编程示例源代码

    底层的指令或核心算法,会使用C/C++处理,涉及数据处理的时候,为了安全和快速开发,会使用Javascript或Python等脚本语言实现数据分析处理。因此,开发者应该学习或掌握语言混合编程。 C++和Java是主流的两种编程...

    基于C++/Python的量化交易研究框架.rar

    目前项目包含了3个主要组成部分:基于C++的核心库、对C++进行包装的Python库、基于Python的交互式工具。 - C++核心库,提供了整体的策略框架,在保证性能的同时,已经考虑了对多线程和多核处理的支持,在未来追求...

    Python基础实例教程部分习题参考答案.zip

    作为脚本语言,Python尽管在速度上比编译语言如C和C++等略有逊色,但其因开放性、跨平台和易学易用的特点获得了众多专业和非专业人士的青睐与支持。然而目前在介绍Python的书目中却难以觅到一本合适的教材,大部分...

    Python和C/C++交互的几种方法总结

    前言 python作为一门脚本语言,其好处是语法简单,很多东西都已经...但是很多时候,我们既想使用python的简介优美,又不想损失太多的性能,这个时候有没有办法将python与C/C++结合到一起呢?这样在性能与速度要求不高的

    Python基础实例教程课件.rar

    作为脚本语言,Python尽管在速度上比编译语言如C和C++等略有逊色,但其因开放性、跨平台和易学易用的特点获得了众多专业和非专业人士的青睐与支持。然而目前在介绍Python的书目中却难以觅到一本合适的教材,大部分...

    执行Python的方式官方解释器交互式运行程序

    Python解释器易于扩展,可以使用C语言或C++(或者其他可以通过C调用的语言)扩展新的功能和数据类型。Python也可用于可定制化软件中的扩展程序语言。Python丰富的标准库,提供了适用于各个主要系统平台的源码或机器...

    Python源码剖析

    ., 为了更好地利用Python语言,无论是使用Python语言本身,还是将Python与C/C++交互使用,深刻理解Python的运行原理都是非常重要的。本书以CPython为研究对象,在C代码一级,深入细致地剖析了Python的实现。书中不仅...

    阿里python入门到精通手册公开发布,企业级教程.pdf

    Python 是⼀个⾼级的编程语⾔,就像我们在⽣活中说的语⾔⼀样,C与C++就像汉语或德语⼀样严谨,Python就像美式英语⼀样,通俗易 懂,使⽤⼴泛,只不过这个语⾔智能说给计算机听。 (简化通俗易懂—⼈⼯智能) Python的...

    python个人学习笔记

    3. 可扩展性好:Python支持多种编程范式,包括面向对象、函数式、过程式等,同时也支持C/C++扩展,可以方便地与其他语言进行交互。 4. 库丰富:Python拥有丰富的标准库和第三方库,可以满足各种需求,如数据处理、...

    Python经典练习题合集(含分析+代码)

    3、Python是一门交互式语言,即其在终端中进行命令编程; 4、Python是一门跨平台的语言【没有操作系统的限制,在任何操作系统上都可以运行Python代码】; 5、Python拥有强大和丰富的库,又被称为胶水语言,能把...

    Python语言程序设计源代码.zip

    与其他高级编程语言如C、C++和Java等相比,Python在数据的表示、处理和可视化方面都有绝对的优势。有编程基础的学习者在学习Python时最好能忘掉以往程序设计语言的语法,彻底转变观念,以全新的姿态融入到Python的...

    Python 2.5

    Python是一个有10年历史的Windows编程语言。Python的创始人为Guido van Rossum。 <br/> <br/>Python是一种即译式的,互动的,面向对象的编程语言,它包含了模组式的操作,异常处理,动态资料形态,十分高...

    Python 网络编程之TCP客户端/服务端功能示例【基于socket套接字】

    本文实例讲述了Python 网络编程之TCP客户端/服务端功能。分享给大家供大家参考,具体如下: demo.py(TCP客户端): import socket def main(): # 1. 创建tcp的套接字 tcp_socket = socket.socket(socket.AF_INET...

    python3.6.0入门指南(官方版)

    Python 解释器可以交互的使用,这使得试 验语言的特性、编写临时程序或在自底向上的程序开发中测试方法非常容易。你甚至还可以把它当做一个桌面计算器。 Python 让程序编写的紧凑和可读。用 Python 编写的程序通常...

    Scratch加减运算 青少年编程 蓝桥杯Scratch编程选拔赛STEMA比赛真题源码

    小兔子编程给小朋友们分享各种少儿编程(Scratch编程、python编程、C++编程等)学习、考级和比赛相关资料;更多少儿编程相关的学习资料,可以访问博主博客 https://blog.csdn.net/frank2102 期待小朋友们相互交流...

    基于C++/Python的开源量化交易研究框架用于策略分析及回测(目前主要用于国内A股市场)

    在进行策略探索时,可以更加专注于某一方面的策略性能与影响性能保障,打造自己的专属应用 目前项目包含了3个主要组成部分:基于C++的核心库、对C++进行包装的Python库(hikyuu)、基于Python的交互式工具。...

    深入浅出VC++ 串口编程 上位机程序

    深入浅出VC++串口编程++上位机程序,包含本人自己搜集的关于VC++、VB平台上上位机与下位机交互、上位机平台的搭建等教程和实例程序。物超所值!

    Scratch影院选座 青少年编程 蓝桥杯Scratch编程选拔赛STEMA比赛真题源码

    小兔子编程给小朋友们分享各种少儿编程(Scratch编程、python编程、C++编程等)学习、考级和比赛相关资料;更多少儿编程相关的学习资料,可以访问博主博客 https://blog.csdn.net/frank2102 期待小朋友们相互交流...

Global site tag (gtag.js) - Google Analytics