当前位置: 首页 > 工具软件 > pybind11 > 使用案例 >

pybind11 使用

邵耀
2023-12-01

简单demo

  1. 建立pycc.cpp
#include <pybind11/pybind11.h>

int add( int i, int j ){
    return i+j;
}

PYBIND11_MODULE( pycc, m ){
    m.doc() = "pybind11 example";
    m.def("add", &add, "add two number" );
}
~
~

 g++ -shared -std=c++11 -fPIC `python -m pybind11 --includes` pycc.cpp -o pycc`python-config --extension-suffix` -I /home/XXX/anaconda3/envs/pytorch-build/bin/python

python端


>>> import pycc
>>> pycc.add(2,3)

make file

CXXFLAGS = -I include  -std=c++11 -O3 $(shell python3-config --cflags)
LDFLAGS = $(shell python3-config --ldflags)

CXX_SOURCES = pycc.cpp

LIB_SO = pycc.so

$(LIB_SO): $(CXX_SOURCES) $(DEPS)
    $(CXX) -o $@ $(CXXFLAGS) $(LDFLAGS) $(CXX_SOURCES) --shared -fPIC

clean:
    rm -rf $(LIB_SO)

2调用类函数的成员函数

pybind11提供了访问成员函数的能力。和访问普通的函数不同,访问成员函数之前先要生成一个对象实例,因此,对任意的一个类而言,都需要有两步,第一步是包装一个实例构造方法,另外一个是成员函数的范围方式

pybind11::class_<命名空间::类名>(m, "在python中构造这个类的方法名" )
        .def(pybind11<>::init())            //构造器,对应的是c++类的构造函数,如果没有这个构造函数,或者参数对不是会调用失败
        .def( "python中函数名", &命名空间::类名::函数名 );
#include <pybind11/pybind11.h>

class Hello
{
public:
    Hello(){}
    void say( const std::string s ){
        std::cout << s << std::endl;
    }
};

PYBIND11_MODULE( py2cpp, m ){
    m.doc() = "pybind11 example";

    pybind11::class_<Hello>(m, "Hello" )
        .def(pybind11::init())
        .def( "say", &Hello::say );
}
//python 调用方式
//1, 先通过构造器来构建实例,方法为 模块名.构造器名
//2,调用对应的方法, 模块名.方法名
//例如本例子需要如下调用
// c=py2cpp.Hello()
// c.say()

调用命名空间中的对象

#include <pybind11/pybind11.h>

namespace NS{
class World{
public:
    World(){}
    void say( const std::string s ){
        std::cout << s << std::endl;
    }
};

PYBIND11_MODULE( py2cpp, m ){
    m.doc() = "pybind11 example";
    pybind11::class_<NS::World>(m, "World")
        .def(pybind11::init())
        .def("say", &NS::World::say);
}

//本例子需要如下调用
// c=py2cpp.World()
// c.say()

带有参数的c++函数的访问

#include <iostream>
#include <pybind11/pybind11.h>

class Test{
public:
    Test( int i, int j )
    :mI(i),mJ(j){

    }

    void Print(){
        std::cout <<"i= " << mI <<" j= " <<mJ << std::endl;
    }
private:
    int mI;
    int mJ;
};

PYBIND11_MODULE( py2cpp, m ){
    m.doc() = "pybind11 example";
    pybind11::class_<Test>(m, "Test" )
        .def( pybind11::init< int , int >() )  //构造器的模版参数列表中需要按照构造函数的参数类型填入才能调用对应的参数
        .def( "print", &Test::Print );
}

//本例子需要如下调用
// c=py2cpp.Test(1,2)
// c.print()

使用stl容器的作为参数的函数

pybind11提供了stl容器的封装类,当需要处理stl容器是,只要额外包括头文件<filepybind11/stl.h>即可。pybin11提供的自动转换包括std::vector<>/std::list<>/std::array<> 转换成 Python list ;std::set<>/std::unordered_set<> 转换成 python set ; andstd::map<>/std::unordered_map<> z转换成dict 几种。至于 std::pair<> 和 std::tuple<>的转换也在 <pybind11/pybind11.h> 头文件中提供了。下面提供一个简单的例子

#include <iostream>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

class ContainerTest{
public:
    ContainerTest(){}
    void Set( std::vector<int> v ){
        mv = v;
    }
    void Print(){
        for( size_t i=0; i<mv.size(); i++ ){
            std::cout << mv[i] << "  " ;
        }
        std::cout << std::endl;
    }
private:
    std::vector<int> mv;
};

PYBIND11_MODULE( py2cpp, m ){
    m.doc() = "pybind11 example";
    pybind11::class_<ContainerTest>(m, "CT" )
        .def( pybind11::init() )
        .def( "set", &ContainerTest::Set )
        .def( "print", &ContainerTest::Print );
}

//本例子需要如下调用
// c=py2cpp.CT()
// c.set( [1,2,3] )
// c.print()

访问struct/class的公有非成员

对于公有非成员变量的访问,pybind11提供了def_readwrite()方法来支持。具体定义如下

#include <pybind11/pybind11.h>

struct ST{
    std::string str;
    uint64_t i;
};

PYBIND11_MODULE( py2cpp, m ){
    m.doc() = "pybind11 example";
    pybind11::class_<ST>(m, "ST")
        .def( pybind11::init() )
        .def_readwrite("str", &ST::str )
        .def_readwrite("i", &ST::i );
}

//本例子需要如下调用
// c = py2cpp.ST()
// c.str="hello"
// c.i = 123
// print(c.str)
// print(c.i)

enum

enum MarkerType { chessboard, tag };

PYBIND11_MODULE( py2cpp, m ){
    m.doc() = "pybind11 example";
    py::enum_<MarkerType>(m, "MarkerType")
         .value("chessboard", MarkerType::chessboard)
         .value("tag",        MarkerType::tag)
         .export_values();
}

参考文章

  • https://zhuanlan.zhihu.com/p/80884925
  • pytorhc c++ 扩展 https://www.cnblogs.com/jermmyhsu/p/10962987.html
  • vc pybind
  • makefile pybind
 类似资料: