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

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

                                         力为 2009

 

一、概念

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

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

      

二、系统架构

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

 1

 

 

系统的运行过程为:

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

 

三、实现

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

 

 

 2

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;
}

 

 

四、结果分析

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

 

 

 3

 

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

 

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

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

 

五、小结

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

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

 

六、广告

4

 

posted on 2009-09-15 20:36  张大大123  阅读(162)  评论(0编辑  收藏  举报

导航