PyBind11五分钟入门【Python/C++调用】

从 Python 调用 C++ 基本上有两种方法:使用 PyBind11 C++ 库生成 Python 模块,或使用 cytpes Python 包访问已编译的共享库。 使用 PyBind11 我们可以更轻松地共享许多数据类型,而使用 ctypes 是一种低级 C 风格的解决方案。

在这里插入图片描述

在线工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器

就我而言,我希望能够利用 C++ 的性能和可移植性,但我不想放弃解释语言的交互性以进行快速探索和调试。

幸运的是,从 Python 调用 C++ 并不像乍看起来那么困难。 这样,我们就可以在开发 C++ 代码的同时掌握 Python 的一些交互性。

就我而言,我想使用 Python 来:

  • 将一些问题参数传递给C++
  • 调用 C++ 代码来运行计算密集型例程
  • 检索最终结果以及一些用于调试的中间计算。
  • 以交互方式探索结果,并生成图表和报告。

使用 ctypes 的问题是共享许多数据类型需要大量的低级解决方法。 例如,虽然 ctypes 不支持复数等基本内容,但 PyBind11 使 Numpy 能够与 Eigen 完全互操作,并且需要最少的代码。

不过,我也发现了 PyBind11 的一个小问题。 事实证明,重新编译 C++ 代码并尝试重新加载 PyBind 生成的 Python 模块后,什么也没发生。 重新加载已编译模块的唯一方法是重新启动我的 Python 会话。 无论如何,这不是什么大问题,因为 Python 的启动时间可以忽略不计。 也许,这个步骤可以在 IDE 级别自动化。

因此,现在的问题是如何充分利用 PyBind11。

1、与 PyBind11 共享 C++ 类

PyBind11 的 官方文档 非常好,我能够毫无问题地开始使用它。 然而,我想分享这个库的超级快速入门指南,以及我打算如何使用它。

Pybind11 是一个仅包含头文件的库,你可以通过以下方式获取它:

pip install pybind11

虽然没有必要将所有 C++ 代码构造为类,但如果你有一个要在 C++ 和 Python 之间共享的类,Pybind11 将使事情变得非常容易。 实际上,我更像是一个struct向量类型的人,我总是想在给定的项目中引入最少数量的类。

然而,在这种情况下,我发现使用外观设计模式(参见 wiki)可以同时带来非常简单的 Python/C++ 互操作性和良好的 API。

所以,我设计了一个简单的类。 它基本上包含:

  • 读取问题参数的构造函数。
  • 执行计算的 run() 函数。
  • 一些 Eigen 数组作为公共变量来存储结果。

这是我的最小示例:

// mylib.h
#include <Eigen/Dense>
#include <cmath>

using Eigen::Matrix, Eigen::Dynamic;
typedef Matrix<std::complex<double>, Eigen::Dynamic, Eigen::Dynamic> myMatrix;

class MyClass {

    int N;
    double a;
    double b;

public:

    Eigen::VectorXd v_data;
    Eigen::VectorXd v_gamma;

    MyClass(){}
    MyClass( double a_in, double b_in, int N_in) 
    {
        N = N_in;
        a = a_in;
        b = b_in;
    }

    void run() 
    { 
        v_data = Eigen::VectorXd::LinSpaced(N, a, b); 

        auto gammafunc = [](double it) { return std::tgamma(it); };
        v_gamma = v_data.unaryExpr(gammafunc);
    }
};

为了共享这个类,我们需要添加一些 C++ 代码。 我倾向于在一个单独的文件中执行此操作,其中包含创建 python 包装器所需的所有内容:

// pywrap.cpp
#include <pybind11/pybind11.h>
#include <pybind11/eigen.h>
#include "mylib.h"

namespace py = pybind11;
constexpr auto byref = py::return_value_policy::reference_internal;

PYBIND11_MODULE(MyLib, m) {
    m.doc() = "optional module docstring";

    py::class_<MyClass>(m, "MyClass")
    .def(py::init<double, double, int>())  
    .def("run", &MyClass::run, py::call_guard<py::gil_scoped_release>())
    .def_readonly("v_data", &MyClass::v_data, byref)
    .def_readonly("v_gamma", &MyClass::v_gamma, byref)
    ;
}

有几点需要强调:

  • 类构造函数签名由 .def(py::init<int, double, double>()) 指定
  • 对于 run() 函数,我们要求释放 GIL(全局解释器锁),这将阻止我们的函数使用多个线程。
  • 最后,可以使用以下 CMakeLists.txt 文件进行编译:
cmake_minimum_required(VERSION 3.10)

project(MyLib)
set(CMAKE_CXX_STANDARD 20)
set(PYBIND11_PYTHON_VERSION 3.6)
set(CMAKE_CXX_FLAGS "-Wall -Wextra -fPIC")

find_package(pybind11 REQUIRED)
find_package(Eigen3 REQUIRED)

pybind11_add_module(${PROJECT_NAME} pywrap.cpp)

target_compile_definitions(${PROJECT_NAME} PRIVATE VERSION_INFO=${EXAMPLE_VERSION_INFO})
target_include_directories(${PROJECT_NAME} PRIVATE ${PYBIND11_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} PRIVATE Eigen3::Eigen)

现在已准备好了。 如果你使用 VS Code,配置 CMake 扩展后,只需按 F7 即可编译 C++ 库。

2、从 Python 调用 C++ 库

这个过程非常简单,并且应该开箱即用。 然而,有一些步骤可以优化交互式工作流程,这些步骤稍微棘手,但也值得实施。

例如,如果正在执行 Python 环境并且编译的库进入构建目录,可以执行以下操作:

import sys
sys.path.append("build/")
from MyLib import MyClass

import matplotlib.pyplot as plt

Simulation = MyClass(-4,4,1000)
Simulation.run()

plt.plot(Simulation.v_data, Simulation.v_gamma, \
"--", linewidth = 3, color=(1,0,0,0.6),label="Function Value")
plt.ylim(-10,10)
plt.xlabel("x")
plt.ylabel("($f(x) = \gamma(x)$)")
plt.title("(Gamma Function: $\gamma(z) = \int_0^\infty x^{z-1} e^{-x} dx$)",fontsize = 18);
plt.show()

结果如下:
在这里插入图片描述

请注意,特征向量会自动转换为 Python 数组。

修改 myLib.hpp 后,只需在 pywrap.cpp 中为我们要公开的每个新函数或变量添加一行代码。

不幸的是,这不会导致完全交互式的工作流程。 当你在更改后重新编译 C++ 代码时,Python 端不会发生任何事情。 即使尝试使用 importtools 重新加载 Python 模块:

import importlib
importlib.reload(MyLib)

什么都没发生。 原因是编译后的代码无法在Python中重新加载。

因此,使用 PyBind11 时,每次重新编译 C++ 代码时都需要重新启动 Python 会话,这对于开发目的来说有点烦人。 然而,这是一个很小的代价,因为 Python 的启动时间可以忽略不计,并且可能有一种方法可以使用一些 IDE 热键或其他工具来自动化该过程。

3、结束语

好了,这就是可以轻松地从 Python 调用 C++ 库的方法。教程的示例代码可以从 github 获取。

特别是,这个两步过程可以产生非常交互式的开发工作流程。 尽管我们有一个编辑-编译-运行工作流程,但我们在最后添加了一个解释器,所以现在我们的工作流程看起来像编辑-编译-运行-探索。

将来,我计划将两个功能合并到此工作流程中:

第一个是 C++20 模块,它应该可以加快大型 C++ 项目的编译时间。 不幸的是,CMake 仍然与模块不兼容(请参阅此问题以获取更新),并且显然必须依赖像 Ninja-Build 这样的构建系统才能立即使用此功能。
另一件事是修复重新编译 C++ 代码后(手动)重新启动 Python 会话的需要。 为此,我希望也许可以在 VSCode 级别对此采取一些措施。 到目前为止,VS Code 中的最佳选项似乎是终止 Python 会话,然后使用 Shift+Enter 执行 Python 代码,如果尚未打开会话,则会创建一个新会话。


原文链接:PyBind11简明教程 — BimAnt

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/133678.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯每日一题2023.11.11

题目描述 “蓝桥杯”练习系统 (lanqiao.cn) 题目分析 对于此题首先想到的是暴力分析&#xff0c;使用前缀和&#xff0c;这样方便算出每一区间的大小&#xff0c;枚举长度和其实位置&#xff0c;循环计算出所有区间的和进行判断&#xff0c;输出答案。 非满分暴力写法&#…

图形界面应用案例——关灯游戏(以及扩展)(python)

7.8 图形界面应用案例——关灯游戏 题目: [案例]游戏初步——关灯游戏。 关灯游戏是很有意思的益智游戏,玩家通过单击关掉(或打开)一盏灯。如果关(掉(或打开)一个电灯,其周围(上下左右)的电灯也会触及开关,成功地关掉所有电灯即可过关。 图7-43 关灯游戏运行效…

Spring中的循环依赖解决方案

前言&#xff1a;测试环境突发BeanCurrentlyInCreationException&#xff0c;导致后端服务启动失败&#xff0c;一看就是Spring的Bean管理中循环依赖。项目中存在Bean的循环依赖&#xff0c;是代码质量低下的表现。多数人寄希望于框架层来给擦屁股&#xff0c;造成了整个代码的…

相机内外参实践之点云投影矢量图

目录 概述 涉及到的坐标变换 深度值可视化 3D点云的2D投影实现 实现效果 参考文献 概述 Camer的内外参在多模态融合中主要涉及到坐标系变换&#xff0c;即像素坐标、相机坐标以及其他坐标系。这篇就针对点云到图像的投影与反投影做代码实践&#xff0c;来构建一张具有深度…

MYSQL 慢查询和慢查询日志

在数据库管理中&#xff0c;慢查询是指执行时间较长的 SQL 查询语句。这类查询可能导致系统性能下降&#xff0c;影响用户体验。为了帮助识别和解决这些性能问题&#xff0c;数据库管理系统通常提供了慢查询日志&#xff0c;用于记录执行时间超过一定阈值的查询。本文将深入探讨…

【pytorch深度学习】使用张量表征真实数据

使用张量表征真实数据 本文为书pytorch深度学习实战的一些学习笔记和扩展知识&#xff0c;涉及到的csv文件等在这里不会给出&#xff0c;但是我会尽量脱离这一些文件将书本想要表达的内容给展示出来。 文章目录 使用张量表征真实数据1. 加载图像文件2. 改变布局3. 加载目录下…

[工业自动化-12]:西门子S7-15xxx编程 - PLC从站 - ET200 SP系列详解

目录 一、概述 1.1 概述 二、系统组成 2.1 概述 2.2 与主站的通信接口模块 2.3 总线适配器 2.4 基座单元 2.5 电子模块 2.6 服务器模块 一、概述 1.1 概述 PLC ET200 SP 是西门子&#xff08;Siemens&#xff09;公司生产的一款模块化可编程逻辑控制器&#xff08;PL…

苹果手机安装未上架APP应用测试教程

STEP 2&#xff1a;找到下载的描述文件&#xff08;如果没有找到&#xff0c;请到 设置 - 通用 - 描述文件 中查看&#xff09; STEP 3&#xff1a;安装描述文件 STEP 4&#xff1a;输入解锁密码安装描述文件 STEP 5&#xff1a;同意免责声明&#xff0c;安装描述文件 STEP 6…

开发知识点-Ant-Design-Vue

Ant-Design-Vue a-input a-input Vue组件 a-spin 加载中的效果 data字段 mounted钩子函数 Ant Design Vue 组件库 list-type“picture-card” 上传的图片作为卡片展示 name show-upload-list action :beforeUpload“handleBeforeUpload” :headers“customHeaders” :disabl…

springboot调用第三方接口json转换成对象

请求接口是一个比较常见的需求&#xff0c;接口返回一般是一个json类型&#xff0c;需要进行组装成对应的类&#xff0c;例 {"status_code": 200,"message": "success","data": {"cost": 286.6933,"bom_list": […

人工智能基础——Python:Matplotlib与绘图设计

人工智能的学习之路非常漫长&#xff0c;不少人因为学习路线不对或者学习内容不够专业而举步难行。不过别担心&#xff0c;我为大家整理了一份600多G的学习资源&#xff0c;基本上涵盖了人工智能学习的所有内容。点击下方链接,0元进群领取学习资源,让你的学习之路更加顺畅!记得…

使用ResponseSelector实现校园招聘FAQ机器人

本文主要介绍使用ResponseSelector实现校园招聘FAQ机器人&#xff0c;回答面试流程和面试结果查询的FAQ问题。FAQ机器人功能分为业务无关的功能和业务相关的功能2类。 一.data/nlu.yml文件   与普通意图相比&#xff0c;ResponseSelector训练数据中的意图采用group/intent格…

Vue 3 打印解决方案:Vue-Plugin-HiPrint

文章目录 1. Vue-Plugin-HiPrint 简介2. 安装和使用2.1 安装2.2 引入并注册插件2.3 在组件中使用 3. 配置和高级用法4. 示例应用5. 总结 &#x1f389;欢迎来到Java学习路线专栏~Vue 3 打印解决方案&#xff1a;Vue-Plugin-HiPrint ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f37…

x3daudio1_7.dll怎么解决?x3daudio1_7.dll丢失的5个详细处理方法

首先&#xff0c;让我们来了解一下X3DAudio1_7.dll丢失的原因。X3DAudio1_7.dll是一个非常重要的动态链接库文件&#xff0c;它负责处理计算机中的音频输出。然而&#xff0c;由于各种原因&#xff0c;例如软件安装错误、病毒感染、系统升级等&#xff0c;我们可能会遇到X3DAud…

超强C语言跨年烟花代码,精美无比,附源码分步解析

现在大家是不是都觉得程序员不懂浪漫&#xff1f;那真的大错特错&#xff0c;今天就让你们看看什么是程序员的浪漫&#xff01; 我们今天就来写写《烟花》表白程序&#xff0c;不要惊讶&#xff0c;不要激动&#xff0c;学会了快去拿给心中的那个人看&#xff01;&#xff01;…

【论文解读】针对生成任务的多模态图学习

一、简要介绍 多模态学习结合了多种数据模式&#xff0c;拓宽了模型可以利用的数据的类型和复杂性&#xff1a;例如&#xff0c;从纯文本到图像映射对。大多数多模态学习算法专注于建模来自两种模式的简单的一对一数据对&#xff0c;如图像-标题对&#xff0c;或音频文本对。然…

玩转ansible之参数调试和文件操作篇

更多IT技术文章&#xff0c;欢迎关注微信公众号“运维之美” 玩转ansible之参数调试和文件操作篇 01 剧本调试和帮助02 使用场景举例 上节我们学习了使用ansible进行软件安装&#xff0c;那么安装完软件后&#xff0c;就需要linux系统和软件配置修改了&#xff0c;对于linux主机…

Java程序设计2023-第八次上机练习

8-1简单文本编辑器 编写简单文本编辑器&#xff0c;该程序可以新建、打开、编辑和保存文本文件。当用户点击New时&#xff0c;新建一个文件&#xff0c;用户可以编辑文件内容&#xff0c;然后点击Save保存文件。用户点击Open时&#xff0c;选择一个已有文件&#xff0c;然后可…

leetcode:206. 反转链表

一、题目 函数原型&#xff1a; struct ListNode* reverseList(struct ListNode* head) 二、思路 要对链表进行反转&#xff0c;可以有两种方法&#xff1a; 1.改变链表中每个结点之间的指针域指向&#xff0c;最后返回尾结点即可。 2.新建一个链表&#xff0c;将原链表中的结点…

gorm之项目实战-使用gen以及定义表间关系

gorm之项目实战 ER图 关系整理 一对一关系&#xff1a; User 和 UserLog&#xff1a; 一个用户对应一个用户日志&#xff0c;通过 User 模型的主键与 UserLog 模型的外键建立一对一关系。 一对多关系&#xff1a; User 和 Teacher&#xff1a; 一个用户可以对应多个老师&…