用Boost.Python将C++代码封装为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++中定义的函数、类等而不必重写。

xuyuan77标注:  如果出现dll无法加载的情况,可以用depends工具查看是否有依赖的dll缺失,比如我在ipython中import  BoostPython_Module_Abs 时无法load dll,是因为 DLLS目录下没有依赖的boost_python3-vc140-mt-x64-1_66.dll文件。

我测试的时候用的是boost 1_66版本,python3.5版本。原作者的代码有很多错误,我注释了代码,只试了import BoostPython_Module_Abs 模块。可以成功运行。

二.     实例篇

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

//boostpython_abs.h
#include <string>
#ifndef BOOSTPYTHON_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 { CANCONNECTED = , CONNECTED, PAUSE, DISCONNECTED }; public: CPhone(std::string owner = "") {} virtual int make_call(int phone_num) = ; virtual std::string make_call(std::string name) = ; virtual CPhone& operator << (int phone_num) = ; virtual CPhone& operator << (std::string name) = ; }; //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); }; #endif//BOOSTPYTHON_ABS_H
//boostpython_abs.cpp

#include <boost/python.hpp>

#include "boostpython_abs.h"
//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<<; int CPhoneWrap::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)) ; enum_<CPhoneWrap::Mode>("Mode") .value("CANCONNECTED", CPhoneWrap::Mode::CANCONNECTED) .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
{
private:
int phone_num; std::string name; CPhone::Mode mode; public: CPerson() {/*initializtion here*/ } CPerson(int num, CPhone::Mode aMode = CPhone::CANCONNECTED)
{
this->mode = aMode;
} void set(int num)
{
this->phone_num = num;
} void set(std::string aName)
{
this->name = aName;
} 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"
#include "boostpython_abs.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)
//
//BOOST_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()
{
return m_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

typedef std::vector<std::string> CStringVector;
void push_back(CStringVector& vec, std::string str) { vec.push_back(str); } std::string pop_back(CStringVector& vec) {
std::string ret = vec.back();
vec.pop_back();
return ret;
} /* * 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/--

'''

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自带文档

转自:http://blog.csdn.net/scuhank/article/details/7769342

【转】利用Boost.Python将C++代码封装为Python模块的更多相关文章

  1. 利用Python中的mock库对Python代码进行模拟测试

    这篇文章主要介绍了利用Python中的mock库对Python代码进行模拟测试,mock库自从Python3.3依赖成为了Python的内置库,本文也等于介绍了该库的用法,需要的朋友可以参考下     ...

  2. 【Selenium05篇】python+selenium实现Web自动化:读取ini配置文件,元素封装,代码封装,异常处理,兼容多浏览器执行

    一.前言 最近问我自动化的人确实有点多,个人突发奇想:想从0开始讲解python+selenium实现Web自动化测试,请关注博客持续更新! 这是python+selenium实现Web自动化第五篇博 ...

  3. python 常忘代码查询 和autohotkey补括号脚本和一些笔记和面试常见问题

    笔试一些注意点: --,23点43 今天做的京东笔试题目: 编程题目一定要先写变量取None的情况.今天就是因为没有写这个边界条件所以程序一直不对.以后要注意!!!!!!!!!!!!!!!!!!!!! ...

  4. <转>机器学习系列(9)_机器学习算法一览(附Python和R代码)

    转自http://blog.csdn.net/han_xiaoyang/article/details/51191386 – 谷歌的无人车和机器人得到了很多关注,但我们真正的未来却在于能够使电脑变得更 ...

  5. python笔记5 接口类抽象类 封装 反射 设计模式 模块 :random随机数 josn shelve持久化存储

    接口类抽象类 接口类:接口类就是制定一个规则,让其他人按照我的规则去写程序. #!/usr/bin/env python from abc import ABCMeta,abstractmethod ...

  6. python之面向对象性封装,多态,以及鸭子类型

    默认类型 class A: class_name = 'python23期' def __init__(self, name, age): self.name = name self.age =age ...

  7. 封装打包Python脚本

    1.前言 封装打包Python的好处,节省了安装各种各样包依赖的问题,同时可以加强我们代码隐私的安全性,这里我的演示环境是Python3.6 ,CentOS7的系统,同时打包工具采用pyinstall ...

  8. Python 坑爹之 代码缩进

    建议:统一使用空格!!!!!!!!!不要Tab Python代码缩进   这两天python-cn邮件列表有一条thread发展的特别长,题目是<python的代码缩进真是坑爹>(地址), ...

  9. 在 C 代码中嵌入 Python 语句或使用 Python 模块 (Visual Studio 2013 环境设置)

    1) 新建一个 内嵌 Python 语句的 C 代码, // This is a test for check insert the Python statements or module in C. ...

随机推荐

  1. H5高德地图获取当前位置

    <!doctype html> <html> <head> <meta charset="utf-8"> <meta http ...

  2. C#时间戳的简单实现

    Introduction: 在项目开发中,我们都经常会用到时间戳来进行时间的存储和传递,最常用的Unix时间戳(TimeStamp)是指格林尼治时间1970年1月1日0时(北京时间1970年1月1日8 ...

  3. linux存储管理之基本分区

    基本分区管理 ====================================================================================基本分区(MBR| ...

  4. PAT 1073 Scientific Notation

    1073 Scientific Notation (20 分)   Scientific notation is the way that scientists easily handle very ...

  5. Oracle 11g streams部署

    环境   源服务器 目标服务器 系统版本 CentOS Linux release 7.3.1611 (Core) CentOS Linux release 7.3.1611 (Core) 主机名 s ...

  6. 牛客练习赛23CD

    链接:https://www.nowcoder.com/acm/contest/156/C 来源:牛客网 题目描述 托米完成了1317的上一个任务,十分高兴,可是考验还没有结束 说话间1317给了托米 ...

  7. python二进制读写文件

    #coding=gbk ''' Created on 2014-5-7 ''' import os.path inputPath = './input.txt' outPath = './out.tx ...

  8. SpringBoot使用CORS解决跨域请求问题

    什么是跨域? 同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源. 同源策略是浏览器安全的基石. 如果一个请求地址里面的协议.域名和端口号都相同,就属于同源. ...

  9. ERROR in Node Sass does not yet support your current environment: Windows 64-bit with Unsupported runtime (64)

    该问题说的是当前环境不支持node-sass,网上说了一下是要安装node 7一下版本才支持. 这里改使用less-loader,及less

  10. E: Sub-process /usr/bin/dpkg returned an error code (1)错误解决

    在用apt-get安装软件时出现了类似于install-info: No dir file specified; try --help for more information.dpkg:处理 get ...