如何从 Python 调用C++

这篇具有很好参考价值的文章主要介绍了如何从 Python 调用C++。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、说明

        Python是一种高级编程语言,它可以调用其他语言编写的函数。在 Python 中调用 C 函数的方法有两种:1)使用 Python 提供的 ctypes 库;2)使用 Python 提供的 Cython 库。

        注意:您可以在此存储库中下载此示例的完整代码。如果您对本文有任何意见,可以在那里开始一个问题,或与我联系。

二、PyBind11 vs ctypes

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

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

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

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

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

        使用 ctypes 的问题在于,共享许多数据类型需要相当多的低级解决方法。例如,虽然ctypes不支持复数等基本的东西,但PyBind11使Numpy与Eigen完全互操作,需要最少的代码。

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

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

三、与 PyBind11 共享C++类

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

        Pybind11 是一个仅标头库,你可以通过以下方式获取它:

 
pip install pybind11

        虽然没有必要将所有C++代码构建为一个类,但如果你有一个类要在C++和 Python 之间共享,Pybind11 会让你的事情变得非常容易。(其实我更像是那种人,总是想介绍给定项目中最少的类数)vectorstruct

        然而,在这种情况下,我发现使用外观设计模式(参见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>())
  • 对于函数,我们希望释放 GIL(全局解释器锁),这将阻止我们的函数使用多个线程。run()

        最后,可以使用以下文件进行编译: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++库。

四、从 Python 调用C++库

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

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

 
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调用c++函数,BOOST C++,python技能小结,python,c++,开发语言

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

        Ater 修改 ,每个我们要公开的新函数或变量只需要添加一行代码。myLib.hpppywrap.cpp

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

 
import importlib
importlib.reload(MyLib)

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

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

五、总结

        因此,这就是您可以轻松地从 Python 调用C++库的方式。

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

        将来,我计划将两个功能合并到此工作流中:文章来源地址https://www.toymoban.com/news/detail-703180.html

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

到了这里,关于如何从 Python 调用C++的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • chatgpt赋能python:Python调用主函数语句

    Python是一种高级编程语言,语法简单,易于学习和使用。在Python程序中,主函数是程序的入口,是程序的核心。本文将介绍Python调用主函数语句的相关知识。 在Python程序中,主函数也称为程序入口函数,是整个程序的核心。主函数通常包含程序的主要逻辑和功能,用于执行程

    2024年02月11日
    浏览(42)
  • python 函数调用

    一、函数的定义 首先语法格式: 二、函数的调用 1.求两个整数的和: 运行结果: 2.关键参数 关键参数指通过对形参赋值的方式传递参数,避免了传递实参过程中,与定义函数的形参顺序不一致的情况。 运行结果: 3.默认参数 在函数定义时参数列表中的某个形参有值,则这

    2024年02月14日
    浏览(45)
  • Python 调用自定义函数

    新手入坑。 通常我们需要把公共函数提出来,作为公共资源调用。也避免了代码的重复书写。 比如我们在项目内创建我们的py脚本路径如下: 在公共方法中定义方法: 在其他脚本中调用如下:

    2024年02月14日
    浏览(57)
  • Python 函数的定义与调用

    ✅作者简介:人工智能专业本科在读,喜欢计算机与编程,写博客记录自己的学习历程。 🍎个人主页:小嗷犬的博客 🍊个人信条:为天地立心,为生民立命,为往圣继绝学,为万世开太平。 🥭本文内容:Python 函数的定义与调用 Python 中使用 def 语句创建函数,其一般的格

    2024年01月25日
    浏览(44)
  • Python中函数间的调用

    本文将详细介绍Python中函数间的调用方法以及如何传递参数、返回值等操作。我们将从以下几个方面进行阐述: Python中函数的调用十分简单,我们只需要在函数名后面加上一对小括号即可。例如: 在上面的例子中,我们定义了两个函数\\\"func1\\\"和\\\"func2\\\",在\\\"func2\\\"函数里面调用了

    2024年02月02日
    浏览(42)
  • Python 函数:定义、调用、参数、递归和 Lambda 函数详解

    函数是一段代码块,只有在调用时才会运行。您可以将数据(称为参数)传递给函数。 函数可以返回数据作为结果。 在Python中,使用def定义函数: 示例 要调用函数,请使用函数名称后跟括号: 示例 可以将信息作为参数传递给函数。参数在函数名称后面的括号内指定

    2024年02月08日
    浏览(75)
  • Python通过函数名调用函数的几种场景

    除了执行系统命令外,我们有时还需要动态地执行一些python代码,有经验的朋友就会知道可以使用内置函数eval实现这一需求,如 eval(\\\"print(__file__)\\\") ,这还是比较简单的。 但如果要动态执行一个函数,讲的资料就会少一点,这次就要看这个需求该如何实现。 1 通过eval调用同一

    2024年04月13日
    浏览(35)
  • chatgpt赋能python:Python如何分行——提高代码可读性和效率的必备技能

    分行,即将一行长代码分为多行,使得代码更加易读、易维护、易修改。 Python作为一门高级编程语言,具有简洁、易读、高效的特点。但在实际编程过程中,难免会遇到较长的代码行,导致代码可读性下降,不利于程序员的开发和维护。因此,Python中分行技术就显得尤为重要

    2024年02月08日
    浏览(43)
  • Python调用C++

    python被称为胶水语言,其优势是能够粘结各种不同的语言。同时,python有着更大的“亲民性”,很容易进行开发。但是,python最大的问题就是 计算速度不够 。通常可以用CUDA或者C++对一个python程序进行加速,加速策略如下: 大规模算术运算、矩阵运算等过程用底层语言这里使

    2024年02月03日
    浏览(25)
  • 【30天python从零到一】---第六天:函数、变量作用域、函数的链式调用和递归调用

    🍎 博客主页:🌙@披星戴月的贾维斯 🍎 欢迎关注:👍点赞🍃收藏🔥留言 🍇系列专栏:🌙 Python专栏 🌙请不要相信胜利就像山坡上的蒲公英一样唾手可得,但是请相信,世界上总有一些美好值得我们全力以赴,哪怕粉身碎骨!🌙 🍉一起加油,去追寻、去成为更好的自己

    2023年04月14日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包