小言_互联网的博客

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

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

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

1. pybind11简介与环境安装

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


  
  1. 直接使用pip安装
  2. pip3 install pybind11
  3. 由于pybind11依赖于pytest,所以在安装前需要先把pytest给安装上
  4. pip3 install pytest

2. 求和函数

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


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

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

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


  
  1. cmake_minimum_required( VERSION 2.8. 12)
  2. project( example)
  3. add_subdirectory( pybind11)
  4. pybind11_add_module( example example.cpp)

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


  
  1. cmake .
  2. make

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

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


  
  1. import example
  2. example.add(3, 4)
  3. [ out]: 7

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

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

返回vector


  
  1. //文件名:func.cpp
  2. #include "func.h"
  3. vector< long> list_square(vector< long> &in_list, vector< long>& out_list){
  4. vector< long>::iterator iter;
  5. for(iter = in_list.begin(); iter != in_list.end(); iter++){
  6. out_list.push_back(*iter * *iter);
  7. }
  8. return out_list;
  9. }
  10. map<string, long> dict_square(map<string, long>& in_dict, map<string, long>& out_dict){
  11. map<string, long>::iterator iter;
  12. iter = in_dict.begin();
  13. while(iter != in_dict.end()){
  14. out_dict.insert({iter->first, iter->second * iter->second});
  15. iter++;
  16. }
  17. return out_dict;
  18. }
  • 写pybind11封装函数

  
  1. //文件名:func_wrapper.cpp
  2. #include <pybind11/pybind11.h>
  3. #include<pybind11/stl.h>
  4. #include "func.h"
  5. PYBIND11_MODULE(square, m){
  6. m.doc() = "Square the members of the container";
  7. m.def( "list_square", &list_square);
  8. m.def( "dict_square", &dict_square);
  9. }

返回struct


  
  1. #include <pybind11/pybind11.h>
  2. #include <iostream>
  3. struct Foo {
  4. std:: string a;
  5. };
  6. void show(Foo f) {
  7. std:: cout << f.a << std:: endl;
  8. }
  9. namespace py = pybind11;
  10. PYBIND11_PLUGIN(example) {
  11. py::module m("example", "pybind11 example plugin");
  12. m.def( "show", &show, "Prints a");
  13. py::class_<Foo>(m, "Foo")
  14. .def_readwrite( "a", &Foo::a);
  15. return m.ptr();
  16. }
  • 写pybind11封装函数

  
  1. import sys
  2. sys.path.append( ".")
  3. import example
  4. b = example. Foo
  5. b.a = "Hello"
  6. 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。

 

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


转载:https://blog.csdn.net/devcloud/article/details/114823765
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场