用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. LeetCode--015--三元之和(java)

    给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中不可以包含重复的三元组. ...

  2. erlang 笔记(06/03/02)

    1 .同时打开的端口数量限制(Open ports) erlang:system_info(port_limit)查询 可以通过环境变量ERL_MAX_PORTS修改,或者配置erlang启动参数(标 ...

  3. php 中swoole安装

    1.下载扩展包: 网址:http://pecl.php.net/ 中(http://pecl.php.net/get/swoole-4.3.1.tgz) 2.解压安装包. 3.进入解压好的安装包. 4 ...

  4. 7.9 GRASP原则九: 隔离变化

    GRASP原则九: 隔离变化  Protected Variations  需求一定会变化的!如何做到以系统的局部变化为代价就可以应对这一点?4.1 GRASP rule9: Protected ...

  5. 『Python』源码解析_从ctype模块理解对象

    1.对象的引用计数 从c代码分析可知,python所有对象的内存有着同样的起始结构:引用计数+类型信息,实际上这些信息在python本体重也是可以透过包来一窥一二的, from ctypes impo ...

  6. gnu make - 初学

    因为要为Linux平台编译ACE,按照ACE的文档如何编译部分的说明,要求使用gnu make.其原文档说明如下: Using the Traditional ACE/GNU Configuratio ...

  7. 绑定的jndi获得connection时,出的错,java.io.NotSerializableException

    求助:java.io.NotSerializableException 最近系统频繁出现Lookup error: java.io.WriteAbortedException: Writing abo ...

  8. 使用Stickers拓展集成iMessage简单功能

    添加一个target,选择Stickers拓展: 然后就会出现iMessage的文件夹:添加你需要的iMessage图片,这里图片遵循下面的要求: Small: 100 x 100 pt @3x sc ...

  9. python文件读写,以后就用with open语句

    读写文件是最常见的IO操作.Python内置了读写文件的函数,用法和C是兼容的. 读写文件前,我们先必须了解一下,在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘, ...

  10. 《JavaScript Dom 编程艺术》读书笔记-第8章

    充实文档的内容,包括几个方面: 一个为文档创建“缩略图列表”的函数: 一个为文档创建“文献来源链接”的函数: 一个为文档创建“快捷键清单”的函数. <abbr>在HTML5 中以取代< ...