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

Visual Studio 2019下使用C++与Python进行混合编程——环境配置与C++调用Python API接口

前言

  1. 在vs2019下使用C++与Python进行混合编程,在根源上讲,Python 本身就是一个C库,那么这里使用其中最简单的一种方法是把Python的C API来嵌入C++项目中,来实现混合编程。
  2. 当前的环境是,win10,IDE是vs2019,python版本是3.9,python的环境是使用Anacond安装的。

一、环境配置

1. 安装Python
首先要安装好Python的库,Python可以直接从官网下载,或者直接在conda里面进行安装。

2.添加环境变量
安装完成之后,添加两个系统环境变量,分别是:PYTHONHOME和PYTHONPATH。
在这里插入图片描述
如果不添加这两个系统环境变量会报以下的错误:

Python path configuration:PYTHONHOME = (not set)PYTHONPATH = (not set)program name = 'python'isolated = 0environment = 1user site = 1import site = 1sys._base_executable = 'C:\\code\\cpp\\PDFToDoc\\x64\\Release\\PDFToDoc.exe'sys.base_prefix = 'C:\\Users\\duole\\anaconda3'sys.base_exec_prefix = 'C:\\Users\\duole\\anaconda3'sys.platlibdir = 'lib'sys.executable = 'C:\\code\\cpp\\PDFToDoc\\x64\\Release\\PDFToDoc.exe'sys.prefix = 'C:\\Users\\duole\\anaconda3'sys.exec_prefix = 'C:\\Users\\duole\\anaconda3'sys.path = ['C:\\Users\\duole\\anaconda3\\python39.zip','.\\DLLs','.\\lib','C:\\code\\cpp\\PDFToDoc\\x64\\Release',]
Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding
Python runtime state: core initialized
ModuleNotFoundError: No module named 'encodings'Current thread 0x000042d4 (most recent call first):
<no Python frame>

3. 创建项目
打开vs2019,创建一个空的新C++项目:
在这里插入图片描述
创建完成后打开项目属于配置包含目录与库目录:
在这里插入图片描述
在附加依赖项目里把python的lib库名添加到里面:
在这里插入图片描述
4.添加代码
在项目里面新添一个main.cpp
在这里插入图片描述
main.cpp里面的代码:

#include <Python.h>int main()
{Py_Initialize();    // 初始化python解释器PyRun_SimpleString("print('hello python')");Py_Finalize();      // 释放资源return 0;
}

然后运行项目
在这里插入图片描述
这样配置就算法成功了。

二、Python C API 调用

为了方便项目测试,在项目根目录下添加一个script目录,在script目录里面创建一个call_python.py的文件。
在这里插入图片描述

2.1 调用Python代码无参函数

C++调用python无参函数流程:

  1. 初始化python接口(Py_Initialize)
  2. 导入依赖库 (PyRun_SimpleString)
  3. 初始化python系统文件路径(PyRun_SimpleString)
  4. 调用python文件名(PyImport_ImportModule)
  5. 获取函数对象(PyObject_GetAttrString)
  6. 调用函数对象(PyObject_CallObject)
  7. 结束python接口调用,释放资源(Py_Finalize)

在call_python.py里面添加代码:

def test():print("hello python to C++")

然后在main.cpp里面进行调用:

int main()
{//1.初始化python接口Py_Initialize();if (!Py_IsInitialized){std::cout << "python init failed" << std::endl;return 1;}//2.导入依赖库PyRun_SimpleString("import sys");//执行py单条语句//3.初始化python系统文件路径,以便访问到python源码文件所在的路径PyRun_SimpleString("sys.path.append('./script')");//4.调用python源码文件,只写文件名,不用写后缀PyObject* module = PyImport_ImportModule("call_python");if (module == nullptr){std::cout << "module not found: call_python" << std::endl;return 1;}//5.获取python文件里面的函数PyObject* test = PyObject_GetAttrString(module, "test");if (!test || !PyCallable_Check(test)){std::cout << "function not found: test" << std::endl;return 1;}//6.调用函数,函数对象与传入参数PyObject_CallObject(test, nullptr);Py_Finalize();return 0;
}

2.2 调用Python代码有参与有返回值的函数

C++调用python有参并有返回的函数流程:

  1. 初始化python接口(Py_Initialize)
  2. 导入依赖库 (PyRun_SimpleString)
  3. 初始化python系统文件路径(PyRun_SimpleString)
  4. 调用python文件名(PyImport_ImportModule)
  5. 获取函数对象(PyObject_GetAttrString)
  6. 传递参数(PyTuple_New,Py_BuildValue)
  7. 调用函数对象(PyObject_CallObject)
  8. 接收函数返回值(PyArg_Parse)
  9. 结束python接口初始化(Py_Finalize)

在call_python.py里面添加代码:

def add(a, b):c = a + bprint(f"{a} + {b} = {c}")return c

然后在main.cpp里面进行调用:

#include <iostream>
#include <Python.h>int main()
{// 1、初始化python接口Py_Initialize();if (!Py_IsInitialized()){std::cout << "python init failed" << std::endl;return 1;}// 2、初始化python系统文件路径,保证可以访问到 .py文件PyRun_SimpleString("import sys");PyRun_SimpleString("sys.path.append('./script')");// 3、调用python文件名,不用写后缀PyObject* module = PyImport_ImportModule("call_python");if (module == nullptr){std::cout << "module not found: call_python" << std::endl;return 1;}// 4、调用函数PyObject* func = PyObject_GetAttrString(module, "add");if (!func || !PyCallable_Check(func)){std::cout << "function not found: add" << std::endl;return 1;}// 5、给 python 传递参数// 函数调用的参数传递均是以元组的形式打包的, 2表示参数个数// 如果函数中只有一个参数时,写1就可以了PyObject* args = PyTuple_New(2);// 0:第一个参数,传入 int 类型的值 1PyTuple_SetItem(args, 0, Py_BuildValue("i", 1));// 1:第二个参数,传入 int 类型的值 2PyTuple_SetItem(args, 1, Py_BuildValue("i", 2));// 6、使用C++的python接口调用该函数PyObject* ret = PyObject_CallObject(func, args);// 7、接收python计算好的返回值int result;// i表示转换成int型变量。// 在这里,最需要注意的是:PyArg_Parse的最后一个参数,必须加上“&”符号PyArg_Parse(ret, "i", &result);std::cout << "return is " << result << std::endl;// 8、结束python接口初始化Py_Finalize();return 0;
}

2.3 调用Python代码类

C++调用python类流程:

  1. 初始化python接口(Py_Initialize)
  2. 初始化python系统文件路径(PyRun_SimpleString)
  3. 调用python文件名(PyImport_ImportModule)
  4. 获取类(PyObject_GetAttrString)
  5. 根据类构造函数实例化对象(PyEval_CallObject)
  6. 获取实例的函数对象(PyObject_GetAttrString)
  7. 传递参数(PyTuple_New,Py_BuildValue)
  8. 调用函数对象(PyObject_CallObject)
  9. 接收函数返回值(PyArg_Parse)
  10. 结束python接口初始化(Py_Finalize)

在call_python.py里面添加代码:

class Person:def __init__(self, name, age):self.name = nameself.age = agedef foo(self):print(f"my name is {self.name}, my age is {self.age}")

然后在main.cpp里面进行调用:

#include <iostream>
#include <Python.h>int main()
{// 1、初始化python接口Py_Initialize();if (!Py_IsInitialized()){std::cout << "python init failed" << std::endl;return 1;}// 2、初始化python系统文件路径,保证可以访问到 .py文件PyRun_SimpleString("import sys");PyRun_SimpleString("sys.path.append('./script')");// 3、调用python文件名,不用写后缀PyObject* module = PyImport_ImportModule("call_python");if (module == nullptr){std::cout << "module not found: call_python" << std::endl;return 1;}// 4、获取类PyObject* cls = PyObject_GetAttrString(module, "Person");if (!cls){std::cout << "class not found: Person" << std::endl;return 1;}// 5、给类构造函数传递参数// 函数调用的参数传递均是以元组的形式打包的, 2表示参数个数// 如果函数中只有一个参数时,写1就可以了PyObject* args = PyTuple_New(2);// 0:第一个参数,传入 int 类型的值 1PyTuple_SetItem(args, 0, Py_BuildValue("s", "jack"));// 1:第二个参数,传入 int 类型的值 2PyTuple_SetItem(args, 1, Py_BuildValue("i", 18));// 6、根据类名实例化对象PyObject* obj = PyObject_CallObject(cls, args);// 7、根据对象得到成员函数PyObject* func = PyObject_GetAttrString(obj, "foo");if (!func || !PyCallable_Check(func)){std::cout << "function not found: foo" << std::endl;return 1;}// 8、使用C++的python接口调用该函数PyObject_CallObject(func, nullptr);// 9、结束python接口初始化Py_Finalize();return 0;
}

相关文章:

Visual Studio 2019下使用C++与Python进行混合编程——环境配置与C++调用Python API接口

前言 在vs2019下使用C与Python进行混合编程,在根源上讲&#xff0c;Python 本身就是一个C库&#xff0c;那么这里使用其中最简单的一种方法是把Python的C API来嵌入C项目中&#xff0c;来实现混合编程。当前的环境是&#xff0c;win10,IDE是vs2019,python版本是3.9&#xff0c…...

STM32F4X RTC

STM32F4X RTC 什么是RTCSTM32F4X RTCSTM32F4X RTC框图STM32F4X RTC计数频率STM32F4X RTC日历STM32F4X RTC闹钟 STM32F4X RTC例程 什么是RTC RTC全程叫Real-Time Clock实时时钟&#xff0c;是MCU中一个用来计时的模块。RTC的一个主要作用是用来显示实时时间&#xff0c;就像日常…...

[git] 如何克隆仓库,进行项目撰写,并绑定自己的远程仓库

摘要&#xff1a;删除.git文件&#xff0c;才可重新绑定远程仓库。 具体步骤&#xff1a; 文件夹右键&#xff0c;进入”Git Bash Here“执行命令 1. 执行 ”git clone 仓库地址“&#xff0c;克隆仓库 2. 在生成的仓库中&#xff0c;删除 .git 文件 3. git init 初始化仓库…...

【C++】模拟实现二叉搜索树的增删查改功能

个人主页&#xff1a;&#x1f35d;在肯德基吃麻辣烫 我的gitee&#xff1a;C仓库 个人专栏&#xff1a;C专栏 文章目录 一、二叉搜索树的Insert操作&#xff08;非递归&#xff09;分析过程代码求解 二、二叉搜索树的Erase操作&#xff08;非递归&#xff09;分析过程代码求解…...

Yolov8-pose关键点检测:模型轻量化创新 | ScConv结合c2f | CVPR2023

💡💡💡本文解决什么问题:ScConv(空间和通道重建卷积),一个即插即用的架构单元,可以可以直接用来替代各种卷积神经网络中的标准卷积。 ScConv | GFLOPs从9.6降低至9,参数量从6482kb降低至6479kb Yolov8-Pose关键点检测专栏介绍:https://blog.csdn.net/m0_637742…...

【洛谷 P1060】[NOIP2006 普及组] 开心的金明 题解(动态规划+01背包)

[NOIP2006 普及组] 开心的金明 题目描述 金明今天很开心&#xff0c;家里购置的新房就要领钥匙了&#xff0c;新房里有一间他自己专用的很宽敞的房间。更让他高兴的是&#xff0c;妈妈昨天对他说&#xff1a;“你的房间需要购买哪些物品&#xff0c;怎么布置&#xff0c;你说…...

什么是CI/CD:持续集成与持续交付?(InsCode AI 创作助手)

在现代软件开发领域&#xff0c;CICD&#xff08;Continuous Integration and Continuous Delivery&#xff09;是一种关键性的开发实践&#xff0c;它有助于提高软件交付的质量和效率。本文将深入探讨CICD的定义、原理和重要性&#xff0c;以及如何在项目中实施CICD流程。 什…...

redis 高可用

Redis 高可用 在web服务器中&#xff0c;高可用是指服务器可以正常访问的时间&#xff0c;衡量的标准是在多长时间内可以提供正常服务&#xff08;99.9%、99.99%、99.999%等等&#xff09;。 但是在Redis语境中&#xff0c;高可用的含义似乎要宽泛一些&#xff0c;除了保证提供…...

什么样的词条可以创建维基百科?

维基百科在国内用得比较少&#xff0c;有一些特殊原因&#xff0c;维基百科的控制权海外&#xff0c;目前维基百科和谷歌是一样的&#xff0c;在国内是无法正常访问的。但做海外推广的朋友都是知道维基百科的&#xff0c;小马识途营销顾问认为它在世界互联网领域的地位&#xf…...

poll epoll初学习

正是select这些缺点&#xff0c;才有了poll 1.I/O多路转接之poll 2.I/O多路转接之epoll 其中的struct epoll_event:...

BMS电池管理系统——电芯需求数据(三)

BMS电池管理系统 文章目录 BMS电池管理系统前言一、有什么基础数据二、基础数据分析1.充放电的截至电压2.SOC-OCV关系表3.充放电电流限制表4.充放电容量特性5.自放电率 总结 前言 在新能源产业中电芯的开发也占有很大部分&#xff0c;下面我们就来看一下电芯的需求数据有哪些 …...

【uniapp】关于小程序输入框聚焦、失焦(输入法占位)的问题

聊天小程序&#xff0c;界面带有输入框&#xff0c;当输入框中聚焦后&#xff0c;底部自动谈起输入法。此时输入框也要随之出现在输入法上方。默认情况下&#xff0c;输入框此时会被输入法覆盖掉。 以下是亲自实践&#xff0c;解决这个问题的方法&#xff1a; 一、小程序大概…...

MySQL的故事——创建高性能的索引

创建高性能的索引 文章目录 创建高性能的索引一、索引基础二、索引的优点三、高性能的索引策略 一、索引基础 要理解MySQL中索引是如何工作的&#xff0c;最简单的方法就是去看看一本书的“索引 ”部分&#xff1a;如果在一本书中找到某个特定主题&#xff0c;一般会先看书的“…...

渗透测试漏洞原理之---【组件安全】

文章目录 1、组件安全概述1.1、常见组件1.1.1、操作系统1.1.2、Web容器1.1.3、中间件1.1.4、数据库1.1.5、开发框架1.1.6、OA系统1.1.7、其他组件 1.2、漏洞复现1.2.1 漏洞复现模板1.2.3、漏洞名称参考1.2.4、漏洞库 2、Apache2.1、Apache HTTPD2.2、Apache Shiro2.3、Apache T…...

uni-app集成mui-player

uni-app集成mui-player&#xff0c;仅说明集成方法&#xff0c;mui-player 相关配置请查看其官网 准备 在uniapp项目根目录新建hybrid目录在hybrid目录下新建html目录在html目录中新建css、js、img等目录&#xff0c;用于存放相关文件 集成 静态webview 在pages目录下新建v…...

力扣(LeetCode)算法_C++—— 两个数组的交集

给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,2,2,1], nums2 [2,2] 输出&#xff1a;[2] 示例 2&#xff1a; 输入&#xff1a;nums1 …...

异步编程 - 12 异步、基于事件驱动的网络编程框架 Netty

文章目录 Netty概述Netty中的一些概念Netty的线程模型Netty Server端Netty Netty 端 TCP半包与粘包问题基于Netty与CompletableFuture实现RPC异步调用 Netty概述 Netty是一个异步、基于事件驱动的网络应用程序框架&#xff0c;其对Java NIO进行了封装&#xff0c;大大简化了TC…...

STM32 Nucleo-144开发板开箱bring-up

文章目录 1. 开篇2. 开发环境搭建2.1 下载官方例程2.2 ST-Link安装 3. STM32F446ZE demo工程3.1 STM32F446ZE简介3.2 跑个demo试一试 1. 开篇 最近做项目&#xff0c;用到STM32F446ZET6这款MCU&#xff0c;为了赶进度&#xff0c;前期软件需要提前开发&#xff0c;于是在某宝买…...

计算机毕业设计 基于SSM的问卷调查管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…...

基于SpringBoot的无忌在线考试系统(源码+讲解+调试运行)做毕设课设均可

技术栈 前后端分离 前端使用: Vue Element Plus 后端使用: SpringBoot Mysql8.0 Mybatis-Plus 功能 分为 管理员端 和 老师端 和 学生端 管理员端 登陆页 ​科目管理 查看所有科目 ,增加 ,修改 ,删除科目 , 模糊搜索课程 ​考试管理 查看所有考试 ,增加 ,修改 ,删除考试 题库…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

【JVM】Java虚拟机(二)——垃圾回收

目录 一、如何判断对象可以回收 &#xff08;一&#xff09;引用计数法 &#xff08;二&#xff09;可达性分析算法 二、垃圾回收算法 &#xff08;一&#xff09;标记清除 &#xff08;二&#xff09;标记整理 &#xff08;三&#xff09;复制 &#xff08;四&#xff…...

关于easyexcel动态下拉选问题处理

前些日子突然碰到一个问题&#xff0c;说是客户的导入文件模版想支持部分导入内容的下拉选&#xff0c;于是我就找了easyexcel官网寻找解决方案&#xff0c;并没有找到合适的方案&#xff0c;没办法只能自己动手并分享出来&#xff0c;针对Java生成Excel下拉菜单时因选项过多导…...

【FTP】ftp文件传输会丢包吗?批量几百个文件传输,有一些文件没有传输完整,如何解决?

FTP&#xff08;File Transfer Protocol&#xff09;本身是一个基于 TCP 的协议&#xff0c;理论上不会丢包。但 FTP 文件传输过程中仍可能出现文件不完整、丢失或损坏的情况&#xff0c;主要原因包括&#xff1a; ✅ 一、FTP传输可能“丢包”或文件不完整的原因 原因描述网络…...

Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践

在 Kubernetes 集群中&#xff0c;如何在保障应用高可用的同时有效地管理资源&#xff0c;一直是运维人员和开发者关注的重点。随着微服务架构的普及&#xff0c;集群内各个服务的负载波动日趋明显&#xff0c;传统的手动扩缩容方式已无法满足实时性和弹性需求。 Cluster Auto…...

pgsql:还原数据库后出现重复序列导致“more than one owned sequence found“报错问题的解决

问题&#xff1a; pgsql数据库通过备份数据库文件进行还原时&#xff0c;如果表中有自增序列&#xff0c;还原后可能会出现重复的序列&#xff0c;此时若向表中插入新行时会出现“more than one owned sequence found”的报错提示。 点击菜单“其它”-》“序列”&#xff0c;…...