Windows 下用 C++ 调用 Python
文章目录
- Part.I Introduction
- Chap.I Information
- Chap.II 预备知识
- Part.II 语法
- Chap.I PyRun_SimpleString
- Chap.II C++ / Python 变量之间的相互转换
- Part.III 实例
- Chap.I 文件内容
- Chap.II 基于 Visual Studio IDE
- Chap.III 基于 cmake
- Chap.IV 运行结果
- Part.IV 可能出现的问题
- Chap.I 无法打开 python311_d.lib
- Chap.II 导入模块报错
- Chap.I PyEval_CallObject 调用报错
- Reference
Part.I Introduction
本文主要介绍一下如何使用 C++ 调用 Python。包括运行 python 脚本;C++ 和 Python 之间参数的相互转换和传递。
Chap.I Information
下面是笔者python 相关的目录,可参考
python.exe
所在目录:A:\Programs\Python\Python11_4
python311.lib
所在目录:A:\Programs\Python\Python11_4\libs
include
所在目录:A:\Programs\Python\Python11_4\include
Chap.II 预备知识
Part.II 语法
Chap.I PyRun_SimpleString
Python 库函数 PyRun_SimpleString 可以执行字符串形式的Python代码。不过在使用 PyRun_SimpleString 之前需要先初始化(Py_Initialize()
),执行完之后需要释放资源Py_Finalize()
,示例:
Py_Initialize();
PyRun_SimpleString("print('Hello!')");
Py_Finalize();
Chap.II C++ / Python 变量之间的相互转换
有待总结和补充,可看下面的实例。
Part.III 实例
Chap.I 文件内容
所用到的几个文件组织结构如下
test
│ CMakeLists.txt
│ hello.py
│ main.cpp
└─build
hello.py
中有两个小函数,内容如下:
def add(a,b):return a+bdef get_name(first):return "your name is {} alice".format(first)
main.cpp
文件内容如下:
#include <iostream>
#include <Python.h>using namespace std;const int kError = -1;
const int kSuccess = 0;/*** @brief Initializes the python interpreter*/
int pythonInit() {Py_Initialize();int ret = Py_IsInitialized();if (ret == 0) {cout << "Py_Initialize error" << endl;return kError;}return kSuccess;
}/*** @brief Release resources requested by Python*/
void pythonCleanup() {Py_Finalize();
}/*** @brief Import module ${name} in ${pyDir}* @param[in] pyDir The path of the python script* @param[in] name The name of the python script* @return the module object*/
PyObject *pythonImportModule(const char *pyDir, const char *name) {// 引入当前路径,否则下面模块不能正常导入char tempPath[256] = {};sprintf(tempPath, "sys.path.append('%s')", pyDir);PyRun_SimpleString("import sys");//PyRun_SimpleString("sys.path.append('./')");PyRun_SimpleString(tempPath);PyRun_SimpleString("print('curr sys.path', sys.path)");// import ${name}PyObject *module = PyImport_ImportModule(name);if (module == nullptr) {PyErr_Print();cout << "PyImport_ImportModule '" << name << "' not found" << endl;return nullptr;}return module;
}/*** @brief Call 'add' function in the python script* @param[in] module The name of module* @param[in] a The value of a* @param[in] b The value of b* @return a + b*/
int callPythonAdd(PyObject *module, int a, int b) {//获取模块字典属性PyObject *pDict = PyModule_GetDict(module);if (pDict == nullptr) {PyErr_Print();std::cout << "PyModule_GetDict error" << std::endl;return kError;}//直接获取模块中的函数PyObject *addFunc = PyDict_GetItemString(pDict, "add");if (addFunc == nullptr) {std::cout << "PyDict_GetItemString 'add' not found" << std::endl;return kError;}// 构造python 函数入参, 接收2// see: https://docs.python.org/zh-cn/3.7/c-api/arg.html?highlight=pyarg_parse#c.PyArg_ParsePyObject *pArg = Py_BuildValue("(i,i)", a, b);//调用函数,并得到 python 类型的返回值PyObject *result = PyEval_CallObject(addFunc, pArg);int ret = 0;//将python类型的返回值转换为c/c++类型PyArg_Parse(result, "i", &ret);return ret;
}/*** @brief Call 'get_name' function in the python script* @param[in] module The name of module* @param[in] firstName The firstname* @param[in] outName The fullname* @return success or not*/
int callPythonGetName(PyObject *module, std::string firstName, std::string &outName) {//获取模块字典属性PyObject *pDict = PyModule_GetDict(module);if (pDict == nullptr) {PyErr_Print();std::cout << "PyModule_GetDict error" << std::endl;return kError;}//直接获取模块中的函数PyObject *addFunc = PyDict_GetItemString(pDict, "get_name");if (addFunc == nullptr) {std::cout << "PyDict_GetItemString 'add' not found" << std::endl;return kError;}// 构造python 函数入参, 接收2// see: https://docs.python.org/zh-cn/3.7/c-api/arg.html?highlight=pyarg_parse#c.PyArg_ParsePyObject *pArg = Py_BuildValue("(s)", firstName.c_str());//调用函数,并得到python类型的返回值PyObject *result = PyEval_CallObject(addFunc, pArg);char *name = nullptr;//将python类型的返回值转换为c/c++类型PyArg_Parse(result, "s", &name);char tempStr[256] = {};int strLen = strlen(name);if (strLen > 256) {return kError;}strcpy(tempStr, name);outName = tempStr;return kSuccess;
}int main() {pythonInit();//直接运行python代码PyRun_SimpleString("print('---------- Hello Python form C/C++ ----------')");PyObject *helloModule = pythonImportModule("../", "hello"); // 这里最好还是给绝对路径吧if (helloModule == nullptr) {return -1;}// call python add functionint result = callPythonAdd(helloModule, 1, 3);cout << "1 + 3 = " << result << endl;// call python get_name functionstd::string fullName;callPythonGetName(helloModule, "summer", fullName);cout << fullName << endl;pythonCleanup();
}
CMakeLists.txt 文件内容等会儿说;build 是一个空文件,生成的二进制文件等放这里面。
Chap.II 基于 Visual Studio IDE
1、首先新建一个工程,将main.cpp
添加进去,然后将hello.py
放在和main.cpp
一样的路径下。
2、将 IDE 上方『解决方案平台』设置为x64
,最好将『解决方案配置』设置为Release
(debug 需要*_d.lib
)
3、将include
添加到 C/C++ 附加包含目录中:项目右键→属性→C/C++→附加包含目录→添加 python 的 include
右键属性→链接器→常规→附加库目录→将 python 的 libs 加进去
3、将*.lib
添加到附加依赖项中:项目右键→属性→链接器→输入→将python311.lib
和python311_d.lib
加进去。
Chap.III 基于 cmake
cmake 自动搜寻 python
CMakeLists.txt
文件内容如下:
cmake_minimum_required( VERSION 3.20 )project( test )set( PRJ_INCLUDE_DIRS )
set( PRJ_COMPILE_FEATURES )
set( PRJ_LIBRARIES )list( APPEND PRJ_COMPILE_FEATURES cxx_std_20 )find_package(Python3 COMPONENTS Interpreter Development)message( STATUS "Python3_FOUND = ${Python3_FOUND} " )
message( STATUS "Python3_INCLUDE_DIRS = ${Python3_INCLUDE_DIRS} " )
message( STATUS "Python3_LIBRARIES = ${Python3_LIBRARIES} " )if( ${Python3_FOUND} )#include_directories(${Python3_INCLUDE_DIRS})
else()message( FATAL_ERROR "Python3 not found, please install it." )
endif()list( APPEND PRJ_INCLUDE_DIRS ${Python3_INCLUDE_DIRS} )
list( APPEND PRJ_LIBRARIES ${Python3_LIBRARIES} )message( STATUS "PRJ_LIBRARIES = ${PRJ_LIBRARIES} " )add_executable( ${PROJECT_NAME}main.cpp
)target_include_directories( ${PROJECT_NAME}PRIVATE ${PRJ_INCLUDE_DIRS}
)target_link_libraries( ${PROJECT_NAME} PRIVATE ${PRJ_LIBRARIES}
)target_compile_features( ${PROJECT_NAME} PRIVATE ${PRJ_COMPILE_FEATURES}
)
用 CMake 编译一下
然后直接跑就可以!
cmake 手动设置 Python 路径
CMakeLists.txt
文件内容如下:
cmake_minimum_required( VERSION 3.20 )project( test )set( PRJ_INCLUDE_DIRS )
set( PRJ_COMPILE_FEATURES )
set( PRJ_LIBRARIES )list( APPEND PRJ_COMPILE_FEATURES cxx_std_20 )set( Python3_INCLUDE_DIRS "A:/Programs/Python/Python11_4/include")
set( Python3_LIBRARIES "A:/Programs/Python/Python11_4/libs/python311.lib""A:/Programs/Python/Python11_4/libs/python311_d.lib" )message( STATUS "Python3_INCLUDE_DIRS = ${Python3_INCLUDE_DIRS} " )
message( STATUS "Python3_LIBRARIES = ${Python3_LIBRARIES} " )list( APPEND PRJ_INCLUDE_DIRS ${Python3_INCLUDE_DIRS} )
list( APPEND PRJ_LIBRARIES ${Python3_LIBRARIES} )message( STATUS "PRJ_LIBRARIES = ${PRJ_LIBRARIES} " )add_executable( ${PROJECT_NAME}main.cpp
)target_include_directories( ${PROJECT_NAME}PRIVATE ${PRJ_INCLUDE_DIRS}
)target_link_libraries( ${PROJECT_NAME} PRIVATE ${PRJ_LIBRARIES}
)target_compile_features( ${PROJECT_NAME} PRIVATE ${PRJ_COMPILE_FEATURES}
)
Chap.IV 运行结果
---------- Hello Python form C/C++ ----------
curr sys.path ['A:\\Programs\\Python\\Python11_4\\python311.zip', 'A:\\Programs\\Python\\Python11_4\\DLLs', 'A:\\Programs\\Python\\Python11_4\\Lib', 'A:\\aWork\\scripts\\test1\\test\\build\\Debug', 'A:\\Programs\\Python\\Python11_4', 'A:\\Programs\\Python\\Python11_4\\Lib\\site-packages', '../']
1 + 3 = 4
your name is summer alice
Part.IV 可能出现的问题
Chap.I 无法打开 python311_d.lib
无法打开 python311_d.lib
的问题:笔者使用的 python 版本是 Python 11.4,它的libs
中没有python311_d.lib
,只有python311.lib
(因为安装的时候没有勾选安装 debug 的 lib),解决方法有三个:
- 不使用
debug
模式运行程序,使用release
或其他模式运行 C++ 程序 - 找到
pyconfig.h
文件(一般在py_dir/include
文件夹下),注释下面的内容(有点危险)
#ifdef _DEBUG
# define Py_DEBUG
#endif
- 安装 python 的 debug 版本库:安装程序→更改→勾选
Download debug binaries (requires VS 2017 or later)
Chap.II 导入模块报错
这种情况下是没有把 python 脚本所在的路径加到sys.path
里面,使用sys.path.append(your_path_xx)
添加一下就可以了。
Chap.I PyEval_CallObject 调用报错
报错内容:
'PyEval_CallObjectWithKeywords': deprecated in 3.9
将PyEval_CallObject
替换为PyObject_CallObject
就行了。
Reference
- Linux 系统下通过 cmake 使 C++ 调用 Python
相关文章:
Windows 下用 C++ 调用 Python
文章目录 Part.I IntroductionChap.I InformationChap.II 预备知识 Part.II 语法Chap.I PyRun_SimpleStringChap.II C / Python 变量之间的相互转换 Part.III 实例Chap.I 文件内容Chap.II 基于 Visual Studio IDEChap.III 基于 cmakeChap.IV 运行结果 Part.IV 可能出现的问题Ch…...
九州金榜|家庭教育一招孩子不在任性
有一次和朋友一块聚餐,邻座是一位妈妈、和她大概七八岁的儿子,小男孩长得很帅气,没有像同龄人那样调皮捣乱,而是和妈妈很温馨的就餐。 看的出来一家人的素质很高,就餐过程中桌面保持的很整洁,交流声音也不…...
爬虫案列 --抖音视频批量爬取
""" 项目名称: 唯品会商品数据爬取 项目描述: 通过requests框架获取网页数据 项目环境: pycharm && python3.8 作者所属: 几许1. 对主页抓包 , 鼠标移动到视频位置视频自动播放获得视频数据包 2. 对视频数据包地址进行解析 , 复制链接 , 进行检索 3. 获…...
【React系列】React中的CSS
本文来自#React系列教程:https://mp.weixin.qq.com/mp/appmsgalbum?__bizMzg5MDAzNzkwNA&actiongetalbum&album_id1566025152667107329) 一. React中的css方案 1.1. react 中的 css 事实上,css 一直是 React 的痛点,也是被很多开发…...
基于Kettle开发的web版数据集成开源工具(data-integration)-应用篇
目录 📚第一章 基本流程梳理📗页面基本操作📗对应后台服务流程 📚第二章 二开思路📗前端📗后端 🔼上一集:基于Kettle开发的web版数据集成开源工具(data-integration)-介绍篇 *️⃣主…...
51单片机三种编译模式的相互关系
51单片机三种编译模式的相互关系 编译模式默认存储类型RAM使用规模变量使用特点SAMLLdata128B片内RAM使用规模CPU访问数据速度快,但存储容量较小COMPACTpdata258B片外分页RAM速度和容量介于上下两者之间LARGExdata64KB片外RAMCPU访问数据的速度较慢,但存…...
java 千帆大模型 流式返回
聊天有两个接口,第一个是获取token, 第二个是聊天接口,具体参照官方文档 下面是流式调用聊天接口,单次的,不含上下文 Value("${qianfan.apiKey}")private String apiKey;Value("${qianfan.secretKey}")private String secretKey;Value("${qianfan.to…...
全新互联网洗衣洗鞋小程序平台新模式
互联网洗衣洗鞋新模式, 全新软件升级 对接各大平台 扩大营销渠道,增加效益!...
js 对于一些脚本中对于url的一些参数获取
js 对于一些脚本中对于url的一些参数获取 获取当前浏览器的链接上的参数(不使用vue / react 等框架)仅用在一些脚本上的使用 获取当前浏览器的链接上的参数(不使用vue / react 等框架)仅用在一些脚本上的使用 const query {} const params new URLSear…...
IEDA中tomcat日志乱码解决
文章目录 乱码样式原因解决方案参考 乱码样式 原因 乱码原因是编码格式的问题,编码格式不统一,导致显示乱码。 解决方案 统一编码格式。 打开tomcat的配置文件,conf/logging.properties,进行如下修改 进入idea的安装文件中,b…...
计算机网络实验(六):三层交换机实现VLAN间路由
一、实验名称:三层交换机实现VLAN间路由 二、实验原理 2.1. VLAN基本配置 在交换网络中,为了实现对物理网络的逻辑划分,引入了VLAN(虚拟局域网)的概念。VLAN通过将不同的设备划分到不同的虚拟网络中,实现了逻辑隔离。基本配置包括在交换机上创建VLAN、将端口划分到相应…...
Flutter中showModalBottomSheet的属性介绍和使用
在Flutter中,showModalBottomSheet是一个常用的工具,用于在屏幕底部显示模态底部面板。了解其属性将帮助您更好地定制和控制底部模态框的外观和行为。 showModalBottomSheet的常用属性 1. context: 类型: BuildContext描述: 表示当前构建上下文&#…...
机器学习 -- k近邻算法
场景 我学习Python的初衷是学习人工智能,满足现有的业务场景。所以必须要看看机器学习这一块。今天看了很久,做个总结。 机器学习分为深度学习和传统机器学习 深度学习 深度学习模型通常非常复杂,包含多层神经网络,每一层都包含…...
安全测试之SSRF请求伪造
前言 SSRF漏洞是一种在未能获取服务器权限时,利用服务器漏洞,由攻击者构造请求,服务器端发起请求的安全漏洞,攻击者可以利用该漏洞诱使服务器端应用程序向攻击者选择的任意域发出HTTP请求。 很多Web应用都提供了从其他的服务器上…...
php composer安装
引言 Composer 是 PHP 中的依赖管理工具。它允许您声明您的项目所依赖的库,并且它将为您管理(安装/更新)它们。 官网链接:Introduction - Composer 安装 要在当前目录中快速安装 Composer,请在终端中运行以下脚本。…...
【MyBatis】MyBatis基础操作
文章目录 前言注解方式书写 MyBatis打印 MyBatis 日志参数传递MyBatis 增加操作返回主键 MyBatis 删除操作MyBatis 修改操作MyBatis 查找操作1. 对查询结果进行别名2. Results注解3. 开启驼峰命名(推荐) XML 配置文件方法书写 MyBatis配置数据库的相关配…...
Automatic merge failed; fix conflicts and then commit the result.如何处理
当你在Git中遇到 “Automatic merge failed; fix conflicts and then commit the result.” 的错误时,这意味着你尝试合并两个分支时出现了冲突。Git无法自动解决这些冲突,因此需要你手动解决。以下是处理这种情况的步骤: 找出冲突文件: 运行…...
一文读懂 $mash 通证 “Fair Launch” 规则(幸运池玩法解读篇)
Solmash 是 Solana 生态中由社区主导的铭文资产 LaunchPad 平台,该平台旨在为 Solana 原生铭文项目,以及通过其合作伙伴 SoBit 跨链桥桥接到 Solana 的 Bitcoin 生态铭文项目提供更广泛的启动机会。有了 Solmash,将会有更多的 Solana 生态的铭…...
Qt3D QGeometryRenderer几何体渲染类使用说明
Qt3D中的QGeometryRenderer派生出来的几何体类包括: Qt3DExtras::QConeMesh, Qt3DExtras::QCuboidMesh, Qt3DExtras::QCylinderMesh, Qt3DExtras::QExtrudedTextMesh, Qt3DExtras::QPlaneMesh, Qt3DExtras::QSphereMesh, Qt3DExtras::QTorusMesh, and Qt3DRender::QMesh 有球…...
pandasDataFrame读和写csv文件
从.csv文件读数据 import pandas as pd# 从CSV文件中读取数据 train_df pd.read_csv("datasets/train01.csv") val_df pd.read_csv("datasets/val01.csv") test_df pd.read_csv("datasets/test01.csv")# 显示数据框的前几行,确保…...
力扣122. 买卖股票的最佳时机 II
动态规划 思路: 假设 dp[i][0] 是第 i 天手上没有股票时的最大利润, dp[i][1] 是第 i 天手上有 1 支股票的最大利润;dp[i][0] 的迁移状态为: dp[i - 1][0],前一天手上已经没有股票,没有发生交易࿱…...
Go语言断言和类型查询
Go语言断言和类型查询 1、类型断言 类型断言(Type Assertion)是一个使用在接口值上的操作,用于检查接口类型变量所持有的值是否实现了期望的接 口或者具体的类型。 在Go语言中类型断言的语法格式如下: // i.(TypeNname) value, ok : x.(T)其中&…...
02 Deep learning algorithm
Neural Networks target: inference(prediction)training my own modelpractical advice for building machine learning systemdecision Tress application: speech(语音识别) ----> images(计算机视觉)—> t…...
代码随想录算法训练营第二十四天 | 回溯算法
理论基础 代码随想录原文 什么是回溯法 回溯也可以叫做回溯搜索法,它是一种搜索的方式。 回溯是递归的副产品,只要有递归就会有回溯。 回溯法的效率 虽然回溯法很难,不好理解,但是回溯法并不是什么高效的算法。因为回溯的本…...
Spring Cloud Gateway 缓存区异常
目录 1、问题背景 2、分析源码过程 3、解决办法 最近在测试环境spring cloud gateway突然出现了异常,在这里记录一下,直接上干货 1、问题背景 测试环境spring cloud gateway遇到以下异常 DataBufferLimitException: Exceeded limit on max bytes t…...
Spring Boot依赖版本声明
链接 官网 Spring Boot文档官网:https://docs.spring.io/spring-boot/docs/https://docs.spring.io/spring-boot/docs/ Spring Boot 2.0.7.RELEASE Spring Boot 2.0.7.RELEASE reference相关:https://docs.spring.io/spring-boot/docs/2.…...
Java项目:109SpringBoot超市仓管系统
博主主页:Java旅途 简介:分享计算机知识、学习路线、系统源码及教程 文末获取源码 一、项目介绍 超市仓管系统基于SpringBootMybatis开发,系统使用shiro框架做权限安全控制,超级管理员登录系统后可根据自己的实际需求配角色&…...
【React系列】Redux(三) state如何管理
本文来自#React系列教程:https://mp.weixin.qq.com/mp/appmsgalbum?__bizMzg5MDAzNzkwNA&actiongetalbum&album_id1566025152667107329) 一. reducer拆分 1.1. reducer代码拆分 我们来看一下目前我们的reducer: function reducer(state ini…...
3D 纹理的综合指南
在线工具推荐:3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 我们经常看到超现实主义的视频游戏和动画电影角色出现在屏幕上。他们皮肤上的…...
LLM之RAG实战(十一)| 使用Mistral-7B和Langchain搭建基于PDF文件的聊天机器人
在本文中,使用LangChain、HuggingFaceEmbeddings和HuggingFace的Mistral-7B LLM创建一个简单的Python程序,可以从任何pdf文件中回答问题。 一、LangChain简介 LangChain是一个在语言模型之上开发上下文感知应用程序的框架。LangChain使用带prompt和few-…...
国外云服务器哪个好/深圳seo优化推广公司
【前言】树的遍历,根据访问自身和其子节点之间的顺序关系,分为前序,后序遍历。对于二叉树,每个节点至多有两个子节点(特别的称为左,右子节点),又有中序遍历。由于树自身具有的递归性…...
真人做爰网站视频教程/安装百度到手机桌面
文|曾响铃 来源|科技向令说(xiangling0815) 一篇《住千万豪宅,吃榨菜,喝二锅头,中产消费寒冬来了》的网文突然在网上爆火,文中描述的现象说明消费确实趋于保守。在这种情况下,本就被电商冲击&…...
自媒体营销推广方案/seo是搜索引擎优化
刚才遇到一个问题,刚刚解决,觉得有必要记录一下。 问题是这样的:后台传到jsp上一个将List转化成JSON串的字符串,而原先的List中放入的是Map元素。将这个JSON串打印出来结果如下: [{"f0":"7908",&q…...
上海定制网站建设公司哪家好/产品的推广及宣传思路
描述USB 总线引出两个首要的链表!一个 USB 总线引出两个首要 的链表,一个为 USB 设备链表,一个为 USB 驱动链表。设备链表包含各种系统中的 USB 设备以及这些设备的所有接口,驱动链表包含 USB 设备驱动程序(usb device driver)和 …...
一个网站要怎么做/谷歌浏览器官网下载
原标题:一个冬天没下雪的北京终于要下雪了?超级计算机:还不能完全确定1月30日,寒潮南下我国中东部,在我国黄淮江淮一线与冷空气交战掀起大范围雨雪天气,局地还可能有暴雪,这是今年新年以来出现的…...
自己做的网站如何赚钱/四川seo优化
Redis哨兵机制,一主二从注:Redis哨兵切换,建议一主多从一、一主二从二、哨兵配置(sentinel.conf)cd /usr/local/redis-ms/1.创建哨兵目录mkdir -p ./sentinel/26001/tmpcp /usr/local/redis/sentinel.conf ./sentinel/26001/2.修改./sentinel…...