写点什么

混合编程:如何用 python11 调用 C++

发布于: 2021 年 03 月 15 日

摘要:在实际开发过程中,免不了涉及到混合编程,比如,对于 python 这种脚本语言,性能还是有限的,在一些对性能要求高的情景下面,还是需要使用 c/c++来完成。


那怎样做呢?我们能使用 pybind11 作为桥梁,pybind11 的优点是对 C++ 11 支持很好,API 比较简单,现在我们就简单记下 Pybind11 的入门操作。

1. pybind11 简介与环境安装


Pybind11 是一个轻量级只包含头文件的库,用于 Python 和 C++ 之间接口转换,可以为现有的 C++ 代码创建 Python 接口绑定。Pybind11 通过 C++ 编译时的自省来推断类型信息,来最大程度地减少传统拓展 Python 模块时繁杂的样板代码, 已经实现了 STL 数据结构、智能指针、类、函数重载、实例方法等到 Python 的转换,其中函数可以接收和返回自定义数据类型的值、指针或引用。


直接使用pip安装
pip3 install pybind11
由于pybind11依赖于pytest,所以在安装前需要先把pytest给安装上
pip3 install pytest
复制代码

2. 求和函数


首先,我们编写一个 C++源文件,命名为 example.cpp。


// pybind11 头文件和命名空间#include <pybind11/pybind11.h>namespace py = pybind11;
int add(int i, int j){ return i + j;}
PYBIND11_MODULE(example, m){ // 可选,说明这个模块是做什么的 m.doc() = "pybind11 example plugin"; //def( "给python调用方法名", &实际操作的函数, "函数功能说明" ). 其中函数功能说明为可选 m.def("add", &add, "A function which adds two numbers", py::arg("i")=1, py::arg("j")=2);}
复制代码


PYBIND11_MODULE()宏函数将会创建一个函数,在由 Python 发起 import 语句时该函数将会被调用。模块名字“example”,由宏的第一个参数指定(千万不能出现引号)。第二个参数"m",定义了一个 py::module 的变量。函数 py::module::def()生成绑定代码,将 add()函数暴露给 Python。

我们使用 CMake 进行编译。首先写一个 CMakeLists.txt。


cmake_minimum_required(VERSION 2.8.12)project(example)
add_subdirectory(pybind11)pybind11_add_module(example example.cpp)
复制代码


就是 CMakeList.txt 和 example.cpp 放在一个目录下面。


cmake .make
复制代码


会生成 example.cpython-36m-x86_64-linux-gnu.so 文件。

这个文件就是 python 可以调用的文件。还是在相同目录下运行 python,进入 python 命令行


import exampleexample.add(3, 4)[out]: 7
复制代码

3. STL 和 python 内建数据类型的对应关系


在使用 python 编程时,常使用内建容器作为函数的参数和返回值,python 语言的这种特性使我们的程序变得非常灵活和易于理解。那么在使用 pybind11 封装 C++实现的函数的时候,如何保留这一特性呢?本文介绍 pybind11 实现 list 和 dict 作为参数及返回值的方法。



返回 vector

//文件名:func.cpp  #include "func.h"   vector<long> list_square(vector<long> &in_list, vector<long>& out_list){      vector<long>::iterator iter;      for(iter = in_list.begin(); iter != in_list.end(); iter++){          out_list.push_back(*iter * *iter);      }      return out_list;  }   map<string, long> dict_square(map<string, long>& in_dict, map<string, long>& out_dict){      map<string, long>::iterator iter;      iter = in_dict.begin();      while(iter != in_dict.end()){          out_dict.insert({iter->first, iter->second * iter->second});          iter++;      }      return out_dict;  }
复制代码

写 pybind11 封装函数

/文件名:func_wrapper.cpp  #include <pybind11/pybind11.h>  #include<pybind11/stl.h>  #include "func.h"    PYBIND11_MODULE(square, m){      m.doc() = "Square the members of the container";      m.def("list_square", &list_square);      m.def("dict_square", &dict_square);  }
复制代码

返回 struct

#include <pybind11/pybind11.h>#include <iostream>struct Foo {    std::string a;};
void show(Foo f) { std::cout << f.a << std::endl;}
namespace py = pybind11;
PYBIND11_PLUGIN(example) { py::module m("example", "pybind11 example plugin");
m.def("show", &show, "Prints a"); py::class_<Foo>(m, "Foo") .def_readwrite("a", &Foo::a);
return m.ptr();}
复制代码

写 pybind11 封装函数

import syssys.path.append(".")import example b = example.Foob.a = "Hello"example.show(b)
复制代码


此外:提供一些常用的参考链接


pybind11 — Seamless operability between C++11 and Python

python调用C++之pybind11入门

python 调用 c++利器–pybind11

基于 pybind11 实现 Python 调用 c++编写的 CV 算法–下 (Linux+Cmake)


跟我一起学习 pybind11 之一

Passing by value #161

pybind11 封装的函数实现内建容器作为参数及返回值


本文分享自华为云社区《混合编程 — python 调用 C++之 pybind11 入门》,原文作者:SNHer。


点击关注,第一时间了解华为云新鲜技术~


发布于: 2021 年 03 月 15 日阅读数: 18
用户头像

提供全面深入的云计算技术干货 2020.07.14 加入

华为云开发者社区,提供全面深入的云计算前景分析、丰富的技术干货、程序样例,分享华为云前沿资讯动态,方便开发者快速成长与发展,欢迎提问、互动,多方位了解云计算! 传送门:https://bbs.huaweicloud.com/

评论

发布
暂无评论
混合编程:如何用python11调用C++