• 【转】利用Boost.Python将C++代码封装为Python模块


    用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 = 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;
    
    };
    
    //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/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自带文档

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

  • 相关阅读:
    回望2010,展望2011
    Java加密解密
    纠正平时代码中一些简单的误区(附代码)(不断收集)
    Android模拟器代理上网
    ExifInterface 获取GPS数据
    用异或加密(Java版)
    解决Conversion to Dalvik format failed: Unable to execute dex: null
    Android如何快速卸载apk
    2010年的最后一天,我又辞工(日记)
    项目管理学习资料(经典)
  • 原文地址:https://www.cnblogs.com/xuyuan77/p/8419482.html
Copyright © 2020-2023  润新知