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

news2024/11/19 0:29:35

从 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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

synchronized的原理和Callable接口

目录 ♫synchronized原理 ♪锁升级 ♪锁优化 ♫Callable接口 ♫synchronized原理 我们知道synchronized锁可以控制多个线程对共享资源的访问&#xff0c;两个线程针对同一变量访问就会产生阻塞等待。而synchronized锁并不是一成不变的&#xff0c;它会根据情况进行一次升级。…

MySQL---存储过程

存储过程的相关概念 是一组为了完成特定功能的sql语句的集合&#xff0c;类似于函数 写好了一个存储过程之后&#xff0c;我们可以像函数一样随时调用sql的集合。 复杂的&#xff0c;需要很多sql语句联合执行完成的任务 存储过程再执行上比sql语句的执行速度更快&#xff0c…

CS224W5.2——Relational and Iterative Classification

本节中&#xff0c;我们介绍用于节点分类的关系分类器和迭代分类。 从关系分类器开始&#xff0c;我们展示了如何基于邻居的标签迭代更新节点标签的概率。然后讨论迭代分类&#xff0c;通过根据邻居的标签及其特征预测节点标签来改进集体分类。 文章目录 1. 框架2. 关系分类3.…

基于SpringBoot的SSMP整合案例(开启日志与分页查询条件查询功能实现)

开启事务 导入Mybatis-Plus框架后&#xff0c;我们可以使用Mybatis-Plus自带的事务&#xff0c;只需要在配置文件中配置即可 使用配置方式开启日志&#xff0c;设置日志输出方式为标准输出mybatis-plus:global-config:db-config:table-prefix: tb_id-type: autoconfiguration:…

【黑客】最适合小白的学习顺序

一、黑客是什么 原是指热心于计算机技术&#xff0c;水平高超的电脑专家&#xff0c;尤其是程序设计人员。但后来&#xff0c;黑客一词已被用于泛指那些专门利用电脑网络搞破坏或者恶作剧的家伙。 二、学习黑客技术的原因 其实&#xff0c;网络信息空间安全已经成为海陆空之…

Python基础教程:类--继承和方法的重写

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 什么是继承 继承就是让类与类之间产生父子关系&#xff0c;子类可以拥有父类的静态属性和方法 继承就是可以获取到另一个类中的静态属性和普通方法&#xff08;并非所有成员&#xff09; 在python中&#xff0c;新建的类可…

【紫光同创国产FPGA教程】——【PGL22G第十一章】以太网传输实验例程

本原创教程由深圳市小眼睛科技有限公司创作&#xff0c;版权归本公司所有&#xff0c;如需转载&#xff0c;需授权并注www.meyesemi.com) 适用于板卡型号&#xff1a; 紫光同创PGL22G开发平台&#xff08;盘古22K&#xff09; 一&#xff1a;盘古22K开发板&#xff08;紫光…

建筑能源管理(9)——公共建筑能源管理技术

现阶段&#xff0c;在我国经济高速发展的同时&#xff0c;也面临着资源有限、能源消费急剧增长、能源供给与需求之间的矛盾日益突出等问题。数据显示&#xff0c;现阶段我国单位GDP的能耗水平是发达国家的3倍左右&#xff0c;这正是能源总体利用率较低所造成的。建筑能耗作为我…

2023年初学者入门 CV 指南概述

计算机视觉&#xff0c;是一个迅速发展的领域&#xff0c;将让你大开眼界。它的核心是教计算机像我们人类一样看和理解视觉信息。这份全面指南&#xff0c;将为我们揭示计算机视觉的基本概念&#xff0c;探索流行的应用程序&#xff0c;并瞥见计算机视觉的未来趋势。 计算机视觉…

FM8317-USB TYPE-C PD 多协议控制器

产品描述&#xff1a; FM8317是一款集成了USB Type-C、USB Power Delivery&#xff08;PD3.0&#xff09;、PPS的多协议端口控制器&#xff0c;为AC-DC适配器、车载充电器等设备提供高性价比的USB Type-C 端口充电解决方案。 FM8317内置的Type-C协议可以支持Type-C设备插入自动…

SparkAi创作系统ChatGPT网站源码+详细搭建部署教程+AI绘画系统+支持GPT4.0+Midjourney绘画

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如…

Leetcode-145 二叉树的后序遍历

递归 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* this…

字节和美团软件测试面试1000问(含文档)

一、Linux系统应用和环境配置 1、Linux系统的操作命令给我说10个&#xff0c;一般用什么工具远程连接Linux服务器&#xff1f; 2、Linux中的日志存储在哪里&#xff1f;怎么查看日志内容&#xff1f; 3、Linux中top和ps命令的区别&#xff1f; 4、Linux命令运行的结果如何写…

iOS 17.2更新:15Pro支持拍摄空间视频!

苹果又为开发者预览版用户推送了iOS 17.2 Beta2测试版的更新&#xff0c;已经注册Apple Beta版软件计划的用户只需打开设置--通用--软件更新即可在线OTA升级至最新的iOS 17.2测试版。 本次更新包大小为750M左右&#xff0c;内部版本号为&#xff08;21C5040g&#xff09;&#…

c语言,将奇数和偶数分类

题目&#xff1a;输入一个整数数组&#xff0c;实现一个函数&#xff0c;来调整该数组中数字的顺序使得数组中所有的奇数位于数组的前半部分&#xff0c;所有偶数位于数组的后半部分。 思路&#xff1a;像冒泡排序那样&#xff0c;相邻两个数比较&#xff0c;两个都是偶数则不…

(免费版?)CLion Nova 强势登陆 C 和 C++ 开发领域

系列文章目录 文章目录 系列文章目录前言一、CLion Nova二、目标三、优势和改进四、显著差异五、如何安装 CLion Nova六、分享您的反馈意见总结 阿纳斯塔西娅-卡扎科娃 2023 年 11 月 9 日 前言 今天&#xff0c;我们宣布推出免费的 CLion 早期预览版&#xff0c;它使用 ReSh…

【Linux】Linux 中关于文件和文件夹的常用命令

Linux 中关于文件和文件夹的常用命令 讲解 Linux 常用命令的文章已经非常多了&#xff0c;而且有的文章也说的非常清楚详细。我们可能不会记住所有的命令&#xff0c;但对于工作中常用的命令应该熟记于心&#xff0c;最好的方式就是多多实践。 我们可以直接或者通过虚机的方式…

24 _ 二叉树基础(下):有了如此高效的散列表,为什么还需要二叉树?

上一节我们学习了树、二叉树以及二叉树的遍历,今天我们再来学习一种特殊的二叉树,二叉查找树。二叉查找树最大的特点就是,支持动态数据集合的快速插入、删除、查找操作。 我们之前说过,散列表也是支持这些操作的,并且散列表的这些操作比二叉查找树更高效,时间复杂度是O(…

Leetcode-101 对称二叉树

递归&#xff1a;主要思想&#xff1a;对称二叉树是左子树的左孩子右子树的右孩子&#xff0c;左子树的右孩子右子树的左孩子&#xff0c;递归实现思路较为清晰 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* Tr…

同城跑腿服务预约小程序的作用如何

无论是互联网服务化加快还是前几年疫情冲击&#xff0c;在同城生活服务场景中出现了很多商机&#xff0c;如外卖跑腿、校园跑腿、代买代送等&#xff0c;无论公司还是个人都借势不断提升自己品牌的影响力&#xff0c;并且依赖朋友圈不断提升生意营收。 同城跑腿品牌不少&#…