实战构建Python和C++混合系统

    技术2026-03-29  7

    实战构建Python和C++混合系统 收藏

    此文于2009-09-16被推荐到首页 如何被推荐?

           关于 C++ Python 之间互相调用的问题,可以查找到很多资料。本文将主要从解决实际问题的角度看如何构建一个 Python C++ 混合系统。

                                             力为 2009

     

    一、概念

        混合系统 :采用多种语言构建的系统。比如 Native C++ dotNet 的混合系统, Python/Lua C++ 的混合系统。

    Python C++ 各有各的优缺点,构建两者混合系统的主要目的就是利用 Python 的灵活性和 C++ 高效性,增加程序的扩展性。当然还有其他好处,此处就不展开谈了。脚本语言有很多,至于为什么不采用其他的(如 Lua Ruby 等),这里也不考虑。脚本语言的采用主要是个人喜好的问题。采用 Lua 可以查到很多资料,以前也曾用 LuaBind实现过

          

    二、系统架构

           混合系统可以简化成如下模型:

     

     

     

    系统的运行过程为:

    首先在应用程序中嵌入脚本语言解析器,然后用脚本语言提供的 C/C++ API 封装已有的 C++ 功能库,再用脚本调用封装的服务。此后,应用层便可以执行脚本里的内容,其效果与应用层直接调用服务层类似。

     

    三、实现

    本例中采用脚本语言 Python ,因此主要工作为在应用层嵌入 Python 解析器,用 Python 封装服务层。为了说明问题,应用层的实现为 PythonConsole.ex ,服务层的实现为 Mythma.dll ,封装层为 MythmaPy.dll

     

     

     

    1 、假定 Mythma.dll 中的一个类为 CHelloWorld

     

    class MythmaAPI CHelloWorld { public:    CHelloWorld(void);     ~ CHelloWorld(void);     void  SetId( int  nId)  { m_Id  =  nId;}    int   GetId()  const   return  m_Id; } private:     int m_Id; } ;

     

     

     

    2 、现在用 Boost.Python 封装该类:

    #include  " HelloWorld.h " #include  < boost / python.hpp > using   namespace  boost::python; BOOST_PYTHON_MODULE(MythmaPy) {    class_ < CHelloWorld > ( " CHelloWorld " )       .def( " SetId " & CHelloWorld::SetId)       .def( " GetId " & CHelloWorld::GetId)       ; }

     

     

    3 、在 Python 脚本中调用该封装

     

    # import MythmaPy from  MythmaPy  import   * world  =  CHelloWorld() world.SetId( 100 ) print  world.GetId()

     

    4 、在 PythonConsole.exe 中嵌入 Python 解析器

     

    int  main( int  argc,  char   ** argv) {     //  Initialize the interpreter    Py_Initialize();     if  (python::handle_exception(exec_mythma))     {        if  (PyErr_Occurred())        {          BOOST_ERROR( " Python Error detected " );          PyErr_Print();       }        else        {          BOOST_ERROR( " A C++ exception was thrown  for which  "              " there was no exception translator registered. " );       }    }     char  ch;    std::cin  >>  ch;     //  Boost.Python doesn't support Py_Finalize yet, so don't call it!     return  boost::report_errors(); }

    PythonConsole 中调用 Python 脚本

     

    void  exec_mythma() {    std::cout  <<   " exec extension module Mythma "   <<  std::endl;    python::dict global;    python:: object  result  =  python::exec_file(        " .//axxscript.py " , global, global);    python:: object  world  =  global[ " world " ];    CHelloWorld &  py  =  python::extract < CHelloWorld &> (world) BOOST_EXTRACT_WORKAROUND;    std::cout  <<  py.GetId()  <<  std::endl;    std::cout  <<   " success! "   <<  std::endl; }

     

    四、结果分析

    到此为止,一切感觉都很良好。但假如现在就运行程序,为得到如下的错误:

     

     

     

     

    假如直接用 Python.exe 运行上面的 Python 脚本,并不会产生错误,切运行结果正确。这是什么原因引起的呢?

     

    从错误提示可以看出加载 MythmaPy 模块失败。这是因为使用 Boost.Python 需要注意一个问题,即在执行脚本之前,需要用 init<ModuleName> 注册封装模块。

    加上次限制后,我们就需要对上面的架构做些调整, MythmaPy.dll 需要暴露接口供 PythonConsole.exe 在恰当的时机调用注册该模块。

     

    五、小结

           搭建混合系统很简单,麻烦的地方在于 API 的封装。即使采用 dotNet 封装 Native C++ 也是麻烦在这个地方。如果采用一种统一的 API 描述方法,使用工具自动生成封装,这样就可以大大简化封装的复杂度,若可以按需生成不同语言的封装,那更是锦上添花了。

    本例的搭建环境为 VS2008 Python2.5 Boost1.38 。完整工程下载 在这里

     

    六、广告

    最新回复(0)