当前位置: 首页 > web >正文

(5)python开发经验

文章目录

      • 1 同时生成dll和py模块
      • 2 pybind11封装回调函数
      • 3 pybind11封装回调获取GIL


更多精彩内容
👉内容导航 👈
👉Qt开发 👈
👉python开发 👈

1 同时生成dll和py模块

由于add_library和pybind11_add_module会冲突,所以想要同时生成dll动态库和py模块,有两种解决办法;

  1. 方法1:使用不同的名称;
  2. 方法2:需要使用cmake子工程。

可以在不修改原代码的情况下通过拓展pybind11代码,生成py模块。

方法1

cmake_minimum_required(VERSION 3.10)
# project(PCBA_TestLib)set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)add_library(testc SHARED test.cpp)# 寻找python库,Interpreter:表示查找 Python 解释器,Development:表示查找 Python 开发包
find_package(Python COMPONENTS Interpreter Development) 
find_package(pybind11 PATHS "D:/Python/Python313/Lib/site-packages/pybind11/share/cmake" REQUIRED)
pybind11_add_module(testPy  toPy.cpptest.cpp) # 使用pybind11_add_module函数生成模块

方法2

  • test.h

    #ifndef TEST_H
    #define TEST_Hextern "C" {
    __declspec(dllexport)
    int add(int a, int b);
    }
    #endif
    
  • test.cpp

    #include "test.h"int add(int a, int b) {return a + b;
    }
  • toPy.cpp

    #include <pybind11/pybind11.h>
    #include "test.h"namespace py = pybind11; // 这里是关键,声明一个命名空间 py// 参数1:模块名,参数2:模块对象
    PYBIND11_MODULE(test, m) 
    { m.doc() = "pybind11 example plugin"; // zh-CN: 这里是模块的描述信息m.def("add", &add, "A function which adds two numbers"); // 这里是关键,声明一个函数 add
    }
    
  • 主CMakeLists.txt

    cmake_minimum_required(VERSION 3.10)add_subdirectory(cLib)
    add_subdirectory(pyLib)
    
  • cLib/CMakeLists.txt

    cmake_minimum_required(VERSION 3.15)project(test)set(SOURCES ../test.h../test.cpp)add_library(${PROJECT_NAME} SHARED ${SOURCES})
    
  • pyLib/CMakeLists.txt

    cmake_minimum_required(VERSION 3.15)project(testPy)# 寻找python库,Interpreter:表示查找 Python 解释器,Development:表示查找 Python 开发包
    find_package(Python COMPONENTS Interpreter Development) 
    find_package(pybind11 PATHS "D:/Python/Python313/Lib/site-packages/pybind11/share/cmake" REQUIRED)set(SOURCES ../test.cpp../toPy.cpp)pybind11_add_module(${PROJECT_NAME} ${SOURCES}) # 使用pybind11_add_module函数生成模块

2 pybind11封装回调函数

使用pybind11封装回调函数,实现将python函数传入c++代码;

方法1:使用pybind11::function,支持自动失败传入类型。

#include <pybind11/pybind11.h>
#include <pybind11/functional.h>namespace py = pybind11; // 这里是关键,声明一个命名空间 py// C++ 函数接受一个 Python 回调
void py_callback(py::function cb) {// 调用前需获取 GIL(自动通过 py::function 管理)cb(123);cb("Hello from C++"); // 传递参数给 Python 回调
}
// 参数1:模块名,参数2:模块对象
PYBIND11_MODULE(testPy, m) 
{ m.doc() = "pybind11 example plugin"; // zh-CN: 这里是模块的描述信息m.def("callback", &py_callback, "Call a Python callback from C++");
}

方法2:使用std::function,必须要包含#include <pybind11/functional.h>

  • 关键要点说明:
    1. 类型转换:pybind11/functional.h头文件已内置std::function与Python callable对象的自动转换
    2. 线程安全:若C++回调可能跨线程调用,需在回调执行时获取GIL:
#include <pybind11/pybind11.h>
#include <pybind11/functional.h>
#include "test.h"// 定义回调函数类型
using CallbackFunc = std::function<void(int)>;// 需要暴露的函数
void std_callback(CallbackFunc callback) 
{// 处理逻辑(示例:累加操作)int result =  2;// 调用 Python 传入的回调if (callback) {callback(result); // 触发 Python 回调}
}// 参数1:模块名,参数2:模块对象
PYBIND11_MODULE(testPy, m) 
{ m.doc() = "pybind11 example plugin"; // zh-CN: 这里是模块的描述信息m.def("process_with_callback", &std_callback, "A function that takes a callback function");
}

python调用:

import testPydef fun(a):print("Hello", a)if __name__ == "__main__":testPy.py_callback(fun)testPy.std_callback(fun)

3 pybind11封装回调获取GIL

若在 C++ 创建的子线程中需要回调 Python 函数、修改 Python 数据结构,必须在此线程中先获取 GIL。

在不修改已有代码的情况下,通过封装实现回调,并且获取GIL。

#include <pybind11/pybind11.h>
#include <pybind11/functional.h>
#include "test.h"
#include <iostream>using CallbackFunc = std::function<void(int)>;
CallbackFunc callback1;// 定义封装回调
void fun(int a)
{py::gil_scoped_acquire acquire; // 手动获取 GILcallback1(a);
}
// 对python暴露的回调接口
void py_std_callback(CallbackFunc callback) 
{callback1 = callback;  // 记录回调函数std_callback(fun); // 将封装的回调函数传入C++
}// 参数1:模块名,参数2:模块对象
PYBIND11_MODULE(testPy, m) 
{ m.doc() = "pybind11 example plugin"; // zh-CN: 这里是模块的描述信息m.def("std_callback", &py_std_callback, "A function that takes a callback function");
}


http://www.xdnf.cn/news/6375.html

相关文章:

  • 组合问题(去重)
  • C++23 新增的查找算法详解:ranges::find_last 系列函数
  • uniapp微信小程序-长按按钮百度语音识别回显文字
  • 印度Rummy游戏支付通道申请策略:技巧类游戏的合规与创新
  • 从零开始学习three.js(18):一文详解three.js中的着色器Shader
  • Spring MVC HttpMessageConverter 的作用是什么?
  • 区块链blog1__合作与信任
  • 电池组PACK自动化生产线:多领域电池生产的“智能引擎”
  • 【美团】后端一面复盘|项目驱动 + 手撕 + JVM + 数据库全面覆盖
  • 重磅发布!OpenAI 推出最新模型 GPT-4.1 系列!
  • 多模态大语言模型arxiv论文略读(七十七)
  • 【氮化镓】HfO2钝化优化GaN 器件性能
  • 【React全栈进阶】从组件设计到性能优化实战指南
  • 什么是TCP协议?它存在哪些安全挑战?
  • K8S Gateway API 快速开始、胎教级教程
  • 无人设备遥控器之无线通讯技术篇
  • 随机矩阵放大的方式 生成相位数据集,用于相位展开
  • 技术更新频繁,团队如何适应变化
  • 什么是接口文档,如何使用,注意事项有哪些
  • 【NLP 74、最强提示词工程 Prompt Engineering 从理论到实战案例】
  • spark和hadoop之间的区别和联系
  • 20250507训练赛补题
  • CCF BDCI基于运营商文本数据的知识库检索(RAG)大赛亚军方案分享
  • 联排半孔PCB如何进行SMT贴片?
  • SymPy | 如何提取指定项的系数
  • 【CTFer成长之路】命令执行RCE
  • 动态规划问题 -- 多状态模型(粉刷房子)
  • ⭐️⭐️⭐️【课时6:如何创建工作流应用】学习总结 ⭐️⭐️⭐️ for《大模型Clouder认证:基于百炼平台构建智能体应用》认证
  • 基于Cholesky分解求解逆矩阵
  • 【autojs】图色识别状态条