C++封装python接口(libboost-python)

Posted SUN_DRAGON

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++封装python接口(libboost-python)相关的知识,希望对你有一定的参考价值。

摘要

在Python技术文档中可以找到关于Python与C++之间相互调用的部分。分别叫做extending和Embedding。可以参考技术文档Extending and Embedding the Python Interpreter。于此同时,还提供了 Python/C API接口Python/C API Reference Manual。虽然对于简单的调用使用起来很方便,但对于复杂的结构、封装和继承,操作较为复杂。因此本文介绍我在项目中使用了libboost-python来对C++进行封装Python接口的心得体会。libboost-python可以满足C++中所有的封装。

CMake配置


FIND_PACKAGE(Boost 1.59.0)
IF(Boost_FOUND)
include_directories($Boost_INCLUDE_DIRS ../venv/local/include/python2.7/ )
SET(Boost_USE_STATIC_LIBS OFF)
SET(Boost_USE_MULTITHREADED ON)
SET(Boost_USE_STATIC_RUNTIME OFF)
FIND_PACKAGE(Boost 1.59.0 COMPONENTS python)
ADD_LIBRARY(pyfaceos SHARED main.cpp faceos.cpp)
target_link_libraries(pyfaceos -ldl $Boost_LIBRARIES)
set_target_properties(pyfaceos PROPERTIES PREFIX “” OUTPUT_NAME “faceos”)
ELSEIF(NOT Boost_FOUND)
MESSAGE(FATAL_ERROR “Unable to find correct Boost version. Did you set BOOST_ROOT?”)
ENDIF()

声明库的名称

BOOST_PYTHON_MODULE(lib name)

类型映射

enum

enum_<Color>("Color")
        .value("RED",RED)
        .value("BLUE",BLUE)
        .value("GREEN",GREEN)
        .export_values();

class/struct

class_<rect>("rect")
        .def_readwrite("left",  &cv_rect_t::left)
        .def_readwrite("top",   &cv_rect_t::top)
        .def_readwrite("right", &cv_rect_t::right)
        .def_readwrite("bottom",&cv_rect_t::bottom)
        .def("somefunc", &rect::somefunc) ;

参数当中如果存在引用,且引用之间或与返回值之间存在相互关系,需要增加调用策略

封装容器

//定义容器封装模板
void IndexError()  PyErr_SetString(PyExc_IndexError, "Index out of range"); 

template<class T>
struct std_item

    typedef typename T::value_type V;
    static V& get(T & x, int i)
    
        if( i<0 ) i+=x.size();
        if( i>=0 && i<x.size() ) 
            //printf("in size\\n");
            return x[i];
        
        IndexError();
    
    static void set(T & x, int i, V const& v)
    
        if( i<0 ) i+=x.size();
        if( i>=0 && i<x.size() ) x[i]=v;
        else IndexError();
    
    static void del(T & x, int i)
    
        if( i<0 ) i+=x.size();
        if( i>=0 && i<x.size() ) 
        
            x.erase(x.begin() + i);
        
        else 
            IndexError();
    
    static void add(T & x, V const& v)
    
        x.push_back(v);
    
;
//定义特定的类型
typedef vector<someclass> VecClass;

//定义接口
 class_<VecClass>("VecClass")
        .def("__len__", &VecClass::size)
        .def("clear", &VecClass::clear)
        .def("append", &std_item<VecClass>::add,
            with_custodian_and_ward<1,2>()) // to let container keep value
        .def("__getitem__", &std_item<someclass>::get,
            return_value_policy<copy_non_const_reference>())
        .def("__setitem__", &std_item<someclass>::set,
            with_custodian_and_ward<1,2>()) // to let container keep value
        .def("__delitem__", &std_item<someclass>::del);

类似地,可以使用这种方法来封装数组,list,map等。

对接ndarray

在之前的工作中,我想将一个ndarray参数传入到C++函数当中,之前使用numeric传入到C++之中,并利用num_util获得到数据内容。该库是对底层Python C API 的封装,但用起来很不方便。

仅使用numeric及boost-python对python对象的封装即可完成数据的传递和获取。

这里着重介绍ndarray的传递,其他可参加参见referrence mannul中的Object Wrappers部分。

//获取ndarray中的指针,容易用到
bp::str s = img.tostring();
char* c_str = bp::extract<char*>(s);
//得到形状
const bp::tuple &shape = bp::extract<bp::tuple>(img.attr("shape"));
int dims = bp::extract<int>(shape.attr("__len__")());
int height = bp::extract<int>(shape[0]);
int width = bp::extract<int>(shape[1]);
//访问单个数据
#include <boost/python/numeric.hpp>
#include <boost/python/tuple.hpp>

// sets the first element in a 2d numeric array
void set_first_element(numeric::array& y, double value)

    y[make_tuple(0,0)] = value;

http://www.boost.org/doc/libs/1_61_0/libs/python/doc/html/tutorial/index.html
http://www.boost.org/doc/libs/1_61_0/libs/python/doc/html/

以上是关于C++封装python接口(libboost-python)的主要内容,如果未能解决你的问题,请参考以下文章

QuantLib 金融计算——自己动手封装 Python 接口

C库如何封装成C++接口

如何使用 C++ 封装的 COM 接口部署 C# 库?

c++ 数据抽象 封装 接口(抽象类)

C++类封装-公用接口与私有实现的分离

C++闭源接口的二次封装