python调用C/C++有不少的方法,如boost.python, swig, ctypes, pybind11等,这些方法有繁有简,而pybind11的优点是对C++ 11支持很好,API比较简单,现在我们就简单记下Pybind11的入门操作。
pybind11简介
pybind11是一个轻量级的只包含头文件的库,它主要是用来在已有的 C++代码的基础上做扩展,它的语法和目标非常像Boost.Python,但Boost.Python为了兼容现有的基本所有的C++编译器而变得非常复杂和庞大,而因此付出的代价是很多晦涩的模板技巧以及很多不必要的对旧版编译器的支持。Pybind11摒弃了这些支持,它只支持python2.7以上以及C++ 11以上的编译器,使得它比Boost.Python更加简洁高效。
在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚合数据类型(aggregate data type)的一类。结构体可以被声明为变量、指针或数组等,用以实现较复杂的数据结构。结构体同时也是一些元素的集合,这些元素称为结构体的成员(member),且这些成员可以为不同的类型,成员一般用名字访问。
结构体、结构体指针作为函数的参数应用的非常广泛,本文介绍如何使用pybind11封装C++结构体作为参数的函数。
一.需求分析
现有名为 student 的结构体,有5个成员变量 name,Chinese,Mathematics,English和total ,构造函数通过name生成实例,成员函数 setName 可以给实例的name赋值; calc 函数接收一个student实例作为参数,通过三门课程的分数计算出总分 total ; 将student,calc封装到包含一个student类和一个calc函数的python模块( abctest )中。二.实现步骤
- 在头文件中定义student结构体,并声明calc函数; 在C++源文件中实现func.cpp函数; 编写pybind11封装函数; 用python编写setup脚本; 编译生成动态链接库; 测试函数功能。
三.代码实现
在头文件中定义student结构体,并声明calc函数
//文件名:whjy.h #include <string> using namespace std; struct student{ string name; int Chinese; int Mathematics; int English; int total; student(string n){ this->name = n; } void setName(string stuName){ this->name = stuName; } }; void calc(struct student&);
在C++源文件中实现func.cpp函数
//文件名:func.cpp #include "whjy.h" #include <string> void calc(struct student& tyh){ tyh.total = tyh.Chinese + tyh.Mathematics + tyh.English; }
编写pybind11封装函数
//文件名:func_wrapper.cpp #include <pybind11/pybind11.h> #include "whjy.h" namespace py = pybind11; PYBIND11_MODULE(abctest, m){ m.doc() = "simple example"; py::class_<student>(m, "student") .def(py::init<string>()) .def("setName", &student::setName) .def_readonly("name", &student::name) .def_readwrite("Chinese", &student::Chinese) .def_readwrite("Mathematics", &student::Mathematics) .def_readwrite("English", &student::English) .def_readwrite("total", &student::total); m.def("calc", &calc); }
用python编写setup脚本
#文件名:setup.py from setuptools import setup, Extension functions_module = Extension( name = 'abctest', sources = ['func.cpp', 'func_wrapper.cpp'], include_dirs = [r'D:softwarepybind11-masterinclude', r'D:softwareAnacondainclude'] ) setup(ext_modules = [functions_module])
编译生成动态链接库
在命令行执行 python setup.py build_ext --inplace
,在当前路径下生成pyd动态库。
测试函数功能
#文件名:test.py import abctest s = abctest.student("小明") s.Chinese = 100 s.Mathematics = 110 s.English =120 abctest.calc(s) print(s.name + ":" + str(s.total) + "分") print("----------------------") s.setName("小红") print(s.name + ":" + str(s.total) + "分")
output:
小明:330分
----------------------
小红:330分