首页 > 编程语言 >[pybind11]为c++项目写python API接口

[pybind11]为c++项目写python API接口

时间:2023-06-18 12:33:33浏览次数:55  
标签:python c++ API module pybind11 cpp def

C++项目的pybind方法有哪些?有什么区别?

以下是主要的python绑定cpp的方法:

方法 年份 代表用户
适用于 CPython 的 C/C++ 扩展模块 1991 标准库
PyBind11(推荐用于 C++) 2015
Cython(推荐用于 C) 2007 gevent、kivy
HPy 2019
mypyc 2017
ctype 2003 oscrypto
cffi 2013 cryptography、pypy
SWIG 1996 crfsuite
Boost.Python 2002
cppyy 2017

其中

  1. ctypes: C 与 Python 绑定, Python 内建模块,通过调用.so动态链接库来使用方法,不需要在c++中有特殊的写法,如果使用c++则需要使用extern c的方式再包装一层
  2. Boost.Python: C++ 与 Python 绑定, Boost 模块
  3. pybind11: C++11 与 Python 绑定, 减去了旧 C++ 支持,更轻量化,需要在编写cpp时处理响应的绑定函数。
  4. CPython python标准库中的方式,需要手写绑定方法

一般使用pybind11多一些,因为更为轻量化,能够轻易地加入c++特性。

怎么使用pybind11为python添加c++扩展?

安装pybind11

注意事项

首先在安装时,应确保c++环境和python环境保持一致,具体来讲,就是输入python后

wildkid1024@debian:~$ python3
Python 3.9.2 (default, Feb 28 2021, 17:03:44) 
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 

会显示python使用的gcc版本号,这里需要和c++项目对应的编译器对应:

wildkid1024@debian:~$ cc --version
cc (Debian 10.2.1-6) 10.2.1 20210110
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

因为笔者使用anaconda的环境,在这里就栽了不少跟头,稍微吐槽以下发现anaconda越来越臃肿和无用。

有两种方式可以安装pybind11,第一种是通过c++的项目引入,一种是通过python库的方式安装

cpp 安装

如果是熟悉cpp的编程方式,则是通过submodule的方式进行导入的,具体而言:

git submodule add https://github.com/pybind/pybind11.git third_party/pybind11
cd third_party/pybind11/
git checkout tags/my-version

相应地需要在cmake编译时将pybind11库添加进来,这里需要注意的是pybind11_add_module里的名称需要和编写cpp扩展中的名称保持一直,否则将保持找不到对应的库。

cmake_minimum_required(VERSION 3.1)
project(start-pybind11 VERSION 0.1.0 LANGUAGES C CXX)

set(MY_PYBIND ${MY_CURR}/third_party/pybind11)

add_subdirectory(${MY_PYBIND})
pybind11_add_module(example_pb example_pb.cpp)

如果想在已有 C++ 动态库上扩展 pybind11 绑定,那么 target_link_libraries 链接该动态库就可以了。

target_link_libraries(example_pb PUBLIC example)

python库安装

使用python库的方式安装比较简单,更适合熟悉python的同学。

  1. 使用 pip 安装 PyBind11:pip install pybind11 或 py -m pip install pybind11。
  2. 在cpp项目目录下,运行 python -m pybind11 --includes 或 py -m pybind11 --includes导入pybind11的库

通过pybind11编写绑定扩展

通过以上安装步骤,已经在cpp项目中添加了pybind11的库,接下来就是使用pybind11编写cpp到pybind的扩展:

首先导入pybind11的头文件:

#include <pybind11/pybind11.h>

然后在要导入的module底部,添加以下方法绑定:

namespace py = pybind11;

PYBIND11_MODULE(superfastcode2, m) {
    m.def("fast_tanh2", &tanh_impl, R"pbdoc(
        Compute a hyperbolic tangent of a single argument expressed in radians.
    )pbdoc");

#ifdef VERSION_INFO
    m.attr("__version__") = VERSION_INFO;
#else
    m.attr("__version__") = "dev";
#endif
}

tanh_impl为对应的cpp函数实现的地址,fast_tanh为导入的方法名称,具体来讲,在python中将通过以下方式进行调用:

import superfastcode2
superfastcode2.fast_tanh2(args)

C++类的绑定

PYBIND11_MODULE(tick_pb, m) {
  m.doc() = "tick_pb bindings";

  py::class_<Tick, std::shared_ptr<Tick>>(m, "Tick")
    .def(py::init<std::int64_t, std::int64_t>())
    .def(py::init<TickEvent, std::int64_t, std::int64_t,
                  TickRunCallback, TickRunCallback>())
    .def_property_readonly("is_running", &Tick::IsRunning)
    .def("start", &Tick::Start)
    .def("stop", &Tick::Stop, "wait_life_over"_a = false)
    .def("get_time_start", &Tick::GetTimeStart)
    .def("set_tick_event", [](Tick &self, const TickEvent &tick_event) {
      self.SetTickEvent(tick_event);
    })
    .def("set_run_beg_callback", [](Tick &self,
        const TickRunCallback &run_beg) {
      self.SetRunBegCallback(run_beg);
    })
    .def("set_run_end_callback", [](Tick &self,
        const TickRunCallback &run_end) {
      self.SetRunEndCallback(run_end);
    })
    .def("wait_life_over", &Tick::WaitLifeOver,
        py::call_guard<py::gil_scoped_release>());
}

py::class_定义了从cpp类到python对象的映射,py::init表示了几种实例化方法,def_property_readonly定义了只读属性对应私有成员变量,def_readwrite定义可读写的公有成员变量,其他按照def,取相应的方法地址即可。

库的导出和使用

cpp项目build之后,会在build目录下产生name.cpython-python_version-arch-linux-gnu.so的文件,需要将该文件移到python的运行导入库下面,或通过sys.path手动添加。

还可以通过编写setup的方式将cpp项目打包为python库:

from setuptools import setup, Extension
import pybind11

cpp_args = ['-std=c++11', '-stdlib=libc++', '-mmacosx-version-min=10.7']

sfc_module = Extension(
    'superfastcode2',
    sources=['module.cpp'],
    include_dirs=[pybind11.get_include()],
    language='c++',
    extra_compile_args=cpp_args,
    )

setup(
    name='superfastcode2',
    version='1.0',
    description='Python package with superfastcode2 C++ extension (PyBind11)',
    ext_modules=[sfc_module],
)

问题排查

1. dynamic module does not define module export function

  1. 检查包名是否一致,即cmake中bind的名称是否和cpp绑定代码中的名称一致。
  2. 检查cc版本是否python编译版本一致
  3. 检查python项目是否包含了编译好的lib路径

相似问题:

ImportError: dynamic module does not define init function
Symbol not found: __Py_ZeroStruct / _PyInstanceMethod_Type
SystemError: dynamic module not initialized properly
The Python interpreter immediately crashes when importing my module

2. Some automatic conversions are optional and require extra headers to be included when compiling your pybind11 module.

  1. 检查是否导入#include <pybind11/functional.h>

文献引用

  1. https://learn.microsoft.com/zh-cn/visualstudio/python/working-with-c-cpp-python-in-visual-studio?view=vs-2022
  2. https://pybind11.readthedocs.io/en/stable/index.html

标签:python,c++,API,module,pybind11,cpp,def
From: https://www.cnblogs.com/wildkid1024/p/17488842.html

相关文章

  • 关于如何使用C++进行编程(不使用数据库的情况下)
    问题描述对于一个长期使用Java连接数据库,实现javaweb编程的软工友友来说,突然在编程任务中不允许连接数据库,就有一点的蒙圈,没有办法,只能去查阅资料啦!问题解决不出意外的话,这次我们就需要使用文件操作来存储数据啦!(然后另外一种方法时json,显然,文件操作更加简单一点、也是更加熟悉......
  • 在线免费ChatGPT,官方api
    作为一款强大的语言模型,ChatGPT在自然语言处理领域享有较高声誉。现在,您可以在我们的在线平台上免费体验ChatGPT的功能了!经过不断地优化和改进,我们的在线聊天机器人已经能够针对各种话题展示出色的回答能力。无论是娱乐、教育、生活还是工作相关的话题,ChatGPT都能带来令人惊喜的......
  • python3.11 安装脚本
    !/usr/bin/envbashauthorYuHaiPengyuminstallwget-yyumupdatewget-yyuminstall-ygccpatchlibffi-develpython-develzlib-develbzip2-develncurses-develsqlite-develreadline-develtk-develgdbm-develdb4-devellibpcap-develxz-develglibcif[......
  • C++异常处理
    需要异常处理的情况程序运行时常会碰到一些异常情况,例如:做除法的时候除数为0;用户输入年龄时输入了一个负数;用new运算符动态分配空间时,空间不够导致无法分配;访问数组元素时,下标越界;打开文件读取时,文件不存在。这些异常情况,如果不能发现并加以处理,很可能会导致程序崩溃。......
  • python自动化办公--pyautogui控制鼠标和键盘操作
    ✅作者简介:热爱科研的算法开发者,Python、Matlab项目可交流、沟通、学习。......
  • 【C++】Effective Modern C++ Key Notes
    [errataveryimportant](https://www.aristeia.com/BookErrata/emc++-errata.html)>Argument,ActualArgument>Parameter,FormalParameter##一类型推导C++98有一套类型推导的规则:用于函数模板的规则。C++11修改了其中的一些规则并增加了两套规则,一套用于auto,一套用于dec......
  • 现代C++学习指南-方向篇
    C++是一门有着四十年历史的语言,先后经历过四次版本大升级(诞生、98、11、17(20),14算小升级)。每次升级都是很多问题和解决方案的取舍。了解这些历史,能更好地帮助我们理清语言的发展脉络。所以接下来我将借它的发展历程,谈一谈我对它的理解,最后给出我认为比较合理的学习路线指南。C++0......
  • Python os 模块练题
    题目1:递归输出目录结构需求描述要求输出E:\worksp_py\os_test下的文件结构参考实现defrecursion_file_info(path,indent=0,maxi=-1):'''按字典顺序输出目录结构:parampath:str路径:paramindent:int首次缩进空格——默认为0,一般不用改变:par......
  • 怎么利用大厂的API将大段音频转成文本
    日常办公中,我们经常要开会和写会议纪要。传统模式下,我们需要非常认真地听会议中每一句话,记下自己认为的核心的话,并在会后经过多次修改形成会议纪要。现在,聪明人已经不那么干了,借助几百块的讯飞录音笔,我们可以一口气录下长达三小时的音频,讯飞还能免费给这些录音笔录制的音频转......
  • 设计 C++ 接口文件的小技巧之 PIMPL
    C++里面有一些惯用法(idioms),如RAII,PIMPL,copy-swap、CRTP、SFINAE等。今天要说的是PIMPL,即PointerToImplementation,指向实现的指针。问题描述在实际的项目中,经常需要定义和第三方/供应商的C++接口。假如有这样一个接口文件:MyInterface.h#include<string>#include<li......