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")
        .value("RED",RED)
        .value("BLUE",BLUE)
        .value("GREEN",GREEN)
        .export_values();

class/struct

class_("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//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 && ielse IndexError();
    }
    static void del(T & x, int i)
    {
        if( i<0 ) i+=x.size();
        if( i>=0 && ielse 
            IndexError();
    }
    static void add(T & x, V const& v)
    {
        x.push_back(v);
    }
};
//定义特定的类型
typedef vector VecClass;

//定义接口
 class_("VecClass")
        .def("__len__", &VecClass::size)
        .def("clear", &VecClass::clear)
        .def("append", &std_item::add,
            with_custodian_and_ward<1,2>()) // to let container keep value
        .def("__getitem__", &std_item::get,
            return_value_policy())
        .def("__setitem__", &std_item::set,
            with_custodian_and_ward<1,2>()) // to let container keep value
        .def("__delitem__", &std_item::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(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 
#include 

// 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)