pybind11快速实现c,c++ 与 python互通

简介

pybind11是一个轻量级的头文件库, 为Python和C、C++实现了类型互通,主要用于为现有C++代码创建Python绑定。它的目标和语法与Boost.Python库相似:通过使用编译时自省来推断类型信息,最大限度地减少传统扩展模块中的模板代码。

Boost是一个庞大而复杂的实用程序库套件,几乎可以与现存的所有C++编译器一起使用。这种兼容性是有代价的:为了支持最古老和最有问题的编译器,必须使用神秘的模板技巧和变通方法。现在与C++11兼容的编译器已经广泛使用,Boost已经包含过于庞大和不必要的依赖。

pybind11是Boost.Python的精简版本,剥离了所有与绑定生成无关的东西。在没有注释的情况下,核心头文件只需要大约4K行代码,并且依赖于Python(2.7或3.5+,或PyPy)和C++标准库。这种紧凑的实现是由于一些新的C++11语言特性(特别是:tuple、lambda函数和变量模板)而实现的。

教程和参考文档在https://pybind11.readthedocs.io/en/latest/提供。源代码可以在https://github.com/pybind/pybind11/获得。

核心功能

以下核心C ++功能可以映射到Python

  • 函数入参和返回值可以是自定义数据结构的值、引用或者指针
  • 实例方法和静态方法
  • 重载
  • 实例属性和静态属性
  • 任意异常类型
  • 枚举
  • 回调
  • 迭代器和range
  • 自定义操作符
  • 单继承和多继承
  • STL数据结构
  • 带有引用计数的智能指针,类似于std::shared_ptr
  • 正确的引用计数的内部引用
  • 带有虚函数和纯虚函数的C ++类可以在Python中扩展

其他有用功能

  • Python 2.7,3.5+和PyPy/PyPy3 7.3支持与实现无关接口。
  • 将C++11 lambda函数与捕获的变量绑定在一起。lambda捕获的数据存储在生成的Python函数对象中。
  • pybind11使用C++11 move constructors 和 move assignment operators从而有效地转换自定义数据类型。
  • 通过Python的buffer协议,可以很容易地公开内部存储的自定义数据类型,比如C++矩阵类型如Eigen和NumPy之间进行快速转换。
  • pybind11可以自动将函数矢量化,以便它们透明地应用于以NumPy数组为参数的所有条目。
  • 只需几行代码就可以支持Python的基于切片的访问和赋值操作。
  • 一切都只包含在几个头文件中,没有必要链接任何其他库。
  • 与Boost.Python比二级制文件更小,编译时间更短,5倍速以上。
  • 函数签名是在编译时预先计算的(使用constexpr),生成更小的二进制文件。
  • 只需很少的额外工作,C ++类型就可以像Python对象一样进行pickled和unpickled。

快速入门

  • 安装

调试环境:ubuntu 20.04.3 LTS

# pip install pybind11
# git clone https://github.com/pybind/pybind11
# cd pybind11/include

创建文件example.cpp

#include 

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

PYBIND11_MODULE(example, m) {
    m.doc() = "pybind11 example plugin"; // optional module docstring

    m.def("add", &add, "A function that adds two numbers");
}

编译执行

#  c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)
# ls
example.cpp  example.cpython-38-x86_64-linux-gnu.so  pybind11
# python
Python 3.8.8 (default, Apr 13 2021, 19:58:26) 
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import example
>>> example.add(1, 2)
3

在c++中调用python

demo.cpp

#include 
#include 

namespace py = pybind11;
using namespace std;

int main()
{
    cout << "Hello PyBind World" << endl;

    // start the interpreter and keep it alive
    py::scoped_interpreter guard{}; 
    py::module math = py::module::import("math");
    py::object result = math.attr("sqrt")(25);
    std::cout << "Sqrt of 25 is: " << result.cast() << std::endl;
}

新建CMakeLists.txt

project(pybind_demo)
cmake_minimum_required(VERSION 3.13)
set(CMAKE_CXX_STANDARD 14)  

include(FetchContent)
FetchContent_Declare(
    pybind11
    GIT_REPOSITORY https://github.com/pybind/pybind11.git
    GIT_TAG        v2.6.2
    GIT_SHALLOW    TRUE
)

FetchContent_MakeAvailable(pybind11)

add_executable(demo demo.cpp)
target_link_libraries(demo PRIVATE pybind11::embed)

编译执行:

$ cmake .
CMake Warning (dev) at CMakeLists.txt:1 (project):
  Policy CMP0048 is not set: project() command manages VERSION variables.
  Run "cmake --help-policy CMP0048" for policy details.  Use the cmake_policy
  command to set the policy and suppress this warning.

  The following variable(s) would be set to empty:

    CMAKE_PROJECT_VERSION
    CMAKE_PROJECT_VERSION_MAJOR
    CMAKE_PROJECT_VERSION_MINOR
    CMAKE_PROJECT_VERSION_PATCH
This warning is for project developers.  Use -Wno-dev to suppress it.

-- pybind11 v2.6.2 
-- Configuring done
-- Generating done
-- Build files have been written to: /home/andrew/code/pybind11/include
$ make
Scanning dependencies of target demo
[ 50%] Building CXX object CMakeFiles/demo.dir/demo.cpp.o
[100%] Linking CXX executable demo
[100%] Built target demo
$ ./demo 
Hello PyBind World
Sqrt of 25 is: 5

以上步骤需要保证对github的访问。参考资料:https://blog.devgenius.io/calling-python-and-c-code-using-pybind-99ab7fefa685

在python中调用c++

example.cpp

#include 

int multiply(int i, int j) {
    return i * j;
}

PYBIND11_MODULE(example, m) {
    m.doc() = "pybind11 example plugin"; // optional module docstring
    m.def("multiply", &multiply, "A function which multiplies two numbers");
}

新建CMakeLists.txt

cmake_minimum_required(VERSION 3.13)
project(pybind_demo)
set(CMAKE_CXX_STANDARD 14)  

include(FetchContent)
FetchContent_Declare(
    pybind11
    GIT_REPOSITORY https://github.com/pybind/pybind11.git
    GIT_TAG        v2.6.2
    GIT_SHALLOW    TRUE
)

FetchContent_MakeAvailable(pybind11)

pybind11_add_module(example example.cpp)
target_compile_features(example PUBLIC cxx_std_14)
set_target_properties(example PROPERTIES SUFFIX ".so")

编译执行:

$ cmake .
-- pybind11 v2.6.2 
-- Configuring done
-- Generating done
-- Build files have been written to: /home/andrew/code/pybind11/include/exmaple
$ make
Scanning dependencies of target example
[ 50%] Building CXX object CMakeFiles/example.dir/example.cpp.o
[100%] Linking CXX shared module example.so
[100%] Built target example
$ ls
CMakeCache.txt  CMakeFiles  cmake_install.cmake  CMakeLists.txt  _deps  example.cpp  example.so  Makefile
$ python
Python 3.8.8 (default, Apr 13 2021, 19:58:26) 
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import example
>>> example.multiply(3, 2)
6

你可能感兴趣的:(pybind11快速实现c,c++ 与 python互通)