现在的位置: 首页 > 综合 > 正文

利用Boost.Python将C++代码封装为Python模块

2018年04月06日 ⁄ 综合 ⁄ 共 7909字 ⁄ 字号 评论关闭

Boost.PythonC++代码封装为Python模块

一.    
基础篇

借助Boost.Python库可以将C/C++代码方便、快捷地移植到python模块当中,实现对python模块的扩充。首先,将C++下的代码编译为动态库,并将生成的动态库命名为封装模块的名字,如:用BOOST_PYTHON_MODULE(Module_Name)宏对需要导出的函数、全局变量、类等导入Python的Module_Name模块,此时生成的动态库需要更名为Module_Name.pyd。然后,将Module_Name.pyd放在python的系统搜索目录中(通常是%PYTHON_PATH%\DLLs目录)。最后,在IDLE
GUI界面或是python脚本中执行import Module_Name,这样就可以在python复用C++中定义的函数、类等而不必重写。

二.    
实例篇

下面的实例代码主要针对抽象类、带默认实现虚函数的类、类的成员函数及操作符重载、带默认参数的函数(包括构造函数)、派生类、纯虚函数、返回对象及字符串的函数等的封装方法,基本概括了C+扩展到python模块的常见类型。

//boostpython_abs.h

#ifndefBOOSTPYTHON_ABS_H

#define BOOSTPYTHON_ABS_H

/*

*brief:

*  wrap c/c++ code as dll and export the class/function interfaces

*  to python as modules with boost-library

*author:

*  hank

*history:

*  created 2012-07-13

*/

#ifndef BSTPABS_API

   
#define
BSTPABS_API __declspec(dllimport)

#else

   
#define
BSTPABS_API __declspec(dllexport)

#endif

/*

1.export the abstract class into python module

2.abstract class with member over-load functions|operators

*/

class BSTPABS_API CPhone

{

public:

   
enum
Mode{ CANCONNET = 0, CONNECTED, PAUSE, DISCONNECTED };

public:

    CPhone(std::string owner = "" ){}

   
virtual
int make_call( int phone_num ) = 0;

  
 
virtual std::string make_call( std::string name ) = 0;

   
virtual
CPhone& operator
<<
( int phone_num ) = 0;

   
virtua
l CPhone& operator
<<
( std::string name ) = 0;

};

#endif//BOOSTPYTHON_ABS_H

//boostpython_abs.cpp

#include <boost/python.hpp>

#include "boostpython_abs.h"

//here,wrap the CPhone class

class CPhoneWrap :public CPhone,

                   public boost::python::wrapper<CPhone>

{

public:

   
int
make_call( int phone_num );

   
std::string
make_call( std::string name );

    CPhone& operator <<( int phone_num );

  
 
CPhone& operator << ( std::string name );

};

//define function pointers of overload functions

int (CPhone::*make_call1)(int) =&CPhone::make_call;

std::string (CPhone::*make_call2)(std::string) =&CPhone::make_call;

CPhone& (CPhone::*o1)(int) =&CPhone::operator<<;

CPhone& (CPhone::*o2)(std::string) =&CPhone::operator<<;

intCPhoneWrap::make_call( int phone_num )

{

   
return this
->get_override("make_call1")();

}

std::string CPhoneWrap::make_call( std::string name )

{

   
return this
->get_override("make_call2")();

}

CPhone& CPhoneWrap::operator << ( int phone_num )

{

   
return
boost::python::call<CPhoneWrap&>(this->get_override("o1").ptr());

}

CPhone& CPhoneWrap::operator <<( std::string name )

{

  
 
return boost::python::call<CPhoneWrap&>(this->get_override("o2").ptr());

}

/*

*  Boost.Python Module Export Code bellow

*/

BOOST_PYTHON_MODULE(BoostPython_Module_Abs)

{

   
using namespace
boost::python;

    class_<CPhoneWrap,boost::noncopyable>( "CPhone" )

        .def( "<<",pure_virtual(o1),return_internal_reference<>() )

        .def( "<<",pure_virtual(o2),return_internal_reference<>() )

        .def( "make_call",pure_virtual(make_call1) )

        .def( "make_call",pure_virtual(make_call2) )

        ;

    class_<CPhoneWrap::Mode>("Mode")

        .value( "CANCONNET",CPhoneWrap::Mode::CANCONNET )

        .value( "CONNECTED",CPhoneWrap::Mode::CONNECTED )

        .value( "PAUSE",CPhoneWrap::Mode::PAUSE )

        .value( "DISCONNECTED",CPhoneWrap::Mode::DISCONNECTED )

        ;

}

//boostpython_com.h

#ifndef BOOSTPYTHON_COM_H

#define BOOSTPYTHON_COM_H

#include "boostpython_abs.h"

#ifndef BSTPCOM_API

  
 
#define BSTPCOM_API __declspec(dllimport)

#else

   
#define
BSTPCOM_API __declspec(dllexport)

#endif

/*

*  1.common class with member over-load functions|operators

*  2.with default parameter in constructor function

*/

class BSTPCOM_API CPerson

{

   
int
phone_num;

   
std::string
name;

    CPhone::Mode mode;

public:

    CPerson(){/*initializtion here*/}

    CPerson(int num , CPhone::Mode mode = CPhone::CANCONNECT){this.mode=mode;}

   
void
set(int num){ phone_num = num;}

   
void
set(std::string name){this.name = name;}

   
void
setall(int num ,std::string name = ""){/*do something here*/}

    CPerson&operator<<(int phone_num){return *this;}

    CPerson&operator<<(std::string name){return *this;}

    CPerson& write(int phone_num){return *this;}

    CPerson& write(std::string name){return *this;}

};

#endif//BOOSTPYTHON_COM_H

 //boostpython_com.cpp

#include <boost/python.hpp>

#include "boostpython_com.h"

/*

* the function pointers of overload functions 

*/

void (CPerson::*set1)(int) = &CPerson::set;

void (CPerson::*set2)(std::string) = &CPerson::set;

CPerson& (CPerson::*write1)(int) = &CPerson::write;

CPerson& (CPerson::*write2)(std::string) = &CPerson::write;

/*

*  Boost.Python Module Export Code bellow

*/

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(setall_overload,setall,1,2)

BOOOST_PYTHON_MODULE(BoostPython_Module_Com)

{

   
using
namespace boost::python;

    class_<CPerson>("CPerson")

        .def(init<int,optional<CPhoneWrap::Mode> >() )

        .def(self<<int() )

        .def(self<<std::string() )

        .def("setall",&CPerson::setall,setall_overload() )

        .def("set",set1)

        .def("set",set2)

        .def("write",write1)

        .def("write",write2)

        ;

}

//boostpython_info.h

#ifndef BOOSTPYTHON_INFO_H

#define BOOSTPYTHON_INFO_H

#include "boostpython_abs.h"

#include "boostpython_com.h"

#include <python.h>  //included in dir %PYTHON_PATH%\include

#include <vector>

#ifndef BSTPINFO_API

   
#define
BSTPINFO_API __declspec(dllimport)

#else

   
#define
BSTPINFO_API __declspec(dllexport)

#endif

/*

*  1. virtual functions with default implements

*  2. stl export

*  3. with char* return function,must wrap it

*  4. global function(c-style)

*/

class BSTPINFO_API CInfo

{

public:

   
virtual
std::string get_info(){return "None Info";}

};

class BSTPINFO_API CMessageInfo :public CInfo

{

public:

  
virtual
std::string get_info(){return "Message Info";}

};

class BSTPINFO_API CContact

{

   
std
::vector<std::string> m_vec;

public:

   
std
::vector<std::string> get_contact_person(){returnm_vec;}

    CInfo* get_contact_style(){return new(std::nothrow)CMessageInfo();}

   
void
set_contact_style(CInfo*){/*todo:xxx*/}

   
char
* get_info(){return "return char* in python";}

    //you should wrap char* f(),however,const char* f() this not needed

    PyObject* get_info_wrap(){return Py_BuildValue("s",get_info());}

};

#endif //BOOSTPYTHON_INFO_H

#include <boost/python.hpp>

#include "boostpython_info.h"

class CInfoWrap :public CInfo,

                 public boost::python::wrapper<CInfo>

{

public:

   
std::string
get_info()

    {

       
if
(boost::python::override g=this->get_override("get_info"))

        {

           
return
get_info();

        }

       
return
CInfo::get_info();

    }

};

class CMessageInfoWrap :public CMessageInfo,

                         public boost::python::wrapper<CMessageInfo>

{

   
std
::string get_info()

    {

       
if
(boost::python::override g=this->get_override("get_info"))

        {

           
return
get_info();

        }

       
return
CMessageInfo::get_info();

    }   

};

//define export methods of string-vector into python

typedefstd::vector<std::string>
CStringVector;

void push_back(CStringVector& vec,std::string str)

{

    vec.push_back(str);

}

std::string pop_back(CStringVector& vec)

{

   
return
vec.pop();

}

/*

*  Boost.Python Module code

*/ 

BOOST_PYTHON_MODULE(BoostPython_Module_Info)

{

   
using
namespace boost::python;

   
//export vector in c++ as list in python

    class_<CStringVector>("CStringVector")

        .def("push_back",push_back)

        .def("pop_back",pop_back)

        .def("__iter__",boost::python::iterator<CStringVector>())

        ;

    class_<CInfoWrap,boost::noncopyable>("CInfo")

        .def("get_info",&CInfo::get_info)

        ;

    class_<CMessageInfoWrap,bases<CInfo>,boost::noncopyable>("CMessageInfo")

        .def("get_info",&CMessageInfo::get_info)

        ;       

    class_<CContact>("CContact")

        .def("get_contact_person",&CContact::get_contact_person)

        .def("get_contact_style",&CContact::get_contact_style,return_value_policy<manage_new_object>)

        .def("set_contact_style",&CContact::set_contact_style)

        .def("get_info",&CContact::get_info_wrap)

        ;

}

#!/bin/python

#demo.py

'''

brief:

   demonstratione of C/C++ dll export into python modules

author:

   hank/2012-07-13

'''

import BoostPython_Module_Abs

import BoostPython_Module_Com

import BoostPython_Module_Info

info = BoostPython_Module_Info.CMessageInfo()

contact = BoostPython_Module_Info.CContact()

contact.set_contact_style(info)

getinfo = contact.get_contact_style()

print(type(getinfo)) #the type should be CMessageInfo instance

chars = contact.get_info()

print(chars)

三.    
参考文献

1.      
http://sourceforge.net/projects/boost/files/boost/1.50.0/boost_1_49_0.zip/download
压缩包自带文档

2.      
python-2.7.2
自带文档

抱歉!评论已关闭.