借助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;
virtual CPhone& operator << ( std::string name ) = 0;
};
#endif//BOOSTPYTHON_ABS_H
//boostpython_abs.cpp
#include
#include "boostpython_abs.h"
//here,wrap the CPhone class
class CPhoneWrap :public CPhone,
public boost::python::wrapper
{
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
}
CPhone& CPhoneWrap::operator <<( std::string name )
{
return boost::python::call
}
/*
* Boost.Python Module Export Code bellow
*/
BOOST_PYTHON_MODULE(BoostPython_Module_Abs)
{
using namespace boost::python;
class_
.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_
.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
#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_
.def(init<int,optional
.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
#include
#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
#include "boostpython_info.h"
class CInfoWrap :public CInfo,
public boost::python::wrapper
{
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
{
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_
.def("push_back",push_back)
.def("pop_back",pop_back)
.def("__iter__",boost::python::iterator
;
class_
.def("get_info",&CInfo::get_info)
;
class_
.def("get_info",&CMessageInfo::get_info)
;
class_
.def("get_contact_person",&CContact::get_contact_person)
.def("get_contact_style",&CContact::get_contact_style,return_value_policy
.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自带文档