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

news2024/12/24 21:02:19

前言

  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 = 0
  environment = 1
  user site = 1
  import site = 1
  sys._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 + b
    print(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 类型的值 1
    PyTuple_SetItem(args, 0, Py_BuildValue("i", 1));
    // 1:第二个参数,传入 int 类型的值 2
    PyTuple_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 = name
        self.age = age

    def 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 类型的值 1
    PyTuple_SetItem(args, 0, Py_BuildValue("s", "jack"));
    // 1:第二个参数,传入 int 类型的值 2
    PyTuple_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;
}

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

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

相关文章

一个帮各位填秋招表格省一点事的浏览器插件

最近应该很多和我一样的双非鼠鼠在秋招等面试&#xff0c;而且处于海投阶段&#xff0c;为了不忘记投了哪些公司&#xff0c;可以用这样一个表格来记录&#xff1a; 其中有些字段&#xff0c;比如状态、投递时间、查看进度的网址其实可以不手动输入&#xff0c;所以搞个插件来…

2023数模国赛C 题 蔬菜类商品的自动定价与补货决策-完整版创新多思路详解(含代码)

题目简评&#xff1a;看下来C题是三道题目里简单一些的&#xff0c;考察的点比较综合&#xff0c;偏数据分析。涉及预测模型和运筹优化(线性规划)&#xff0c;还设了一问开放型问题&#xff0c;适合新手入门&#xff0c;发挥空间大。 题目分析与思路&#xff1a; 背景&#x…

部署zookeeper集群

zookeeper和jdk下载地址 jdk 链接&#xff1a;https://pan.baidu.com/s/13GpNaAiHM5HSDJ66ebBtEg 提取码&#xff1a;90se zookeeper 链接&#xff1a;https://pan.baidu.com/s/1nSFKEhSGNiwgSPZWdb7hkw 提取码&#xff1a;u5l2 在所有的机器上面执行下面步骤&#xff1a; 1.上…

C++的纯虚函数和抽象类

在C++中,可以将虚函数声明为纯虚函数,语法格式为: virtual 返回值类型 函数名 (函数参数) = 0; 纯虚函数没有函数体,只有函数声明,在虚函数声明的结尾加上=0,表明此函数为纯虚函数。 最后的=0并不表示函数返回值为0,它只起形式上的作用,告诉编译系统“这是纯虚函数”。…

继承的偏移量问题

下面是实际测试&#xff1a; p1 p3 ! p2 Base1* p1 &d; Derive* p3 &d;! Base2* p2 &d; 图解&#xff1a;

斯坦福小镇升级版——AI-Town搭建指南

导语&#xff1a; 8月份斯坦福AI小镇开源之后&#xff0c;引起了 AIGC 领域的强烈反响&#xff0c;但8月份还有另一个同样非常有意义的 AI-Agent 的项目开源&#xff0c;a16z主导的 AI-Town 本篇文章主要讲解如何搭建该项目&#xff0c;如有英文基础或者对这套技术栈熟悉&#…

监控系统prometheus部署

wget -c https://github.com/prometheus/prometheus/releases/downloa d/v2.37.1/prometheus-2.37.1.linux-amd64.tar.gz下载必要的组件。 mkdir -p /opt/prometheus创建目录。 此文章为9月Day 8学习笔记&#xff0c;内容来源于极客时间《运维监控系统实战笔记》。

docker安装开发常用软件MySQL,Redis,rabbitMQ

Docker安装 docker官网&#xff1a;Docker: Accelerated Container Application Development docker镜像仓库&#xff1a;https://hub.docker.com/search?qnginx 官网的安装教程&#xff1a;Install Docker Engine on CentOS | Docker Docs 安装步骤 1、卸载以前安装的doc…

Reqable项目技术栈全方面总结

大家好&#xff0c;最近有知乎网友问我Reqable技术选型的问题&#xff0c;恰好Reqable也刚刚发布了非常重要的1.3版本更新&#xff0c;所以此次写一篇关于Reqable项目技术栈的全方面总结。 本篇文章的目的&#xff0c;是向大家分享我关于Reqable项目的一些技术思考、细节和填坑…

鸿蒙应用程序入口UIAbility详解

一、UIAbility概述 UIAbility是一种包含用户界面的应用组件&#xff0c;主要用于和用户进行交互。UIAbility也是系统调度的单元&#xff0c;为应用提供窗口在其中绘制界面。每一个UIAbility实例&#xff0c;都对应于一个最近任务列表中的任务。一个应用可以有一个UIAbility&am…

Kafka生产与消费示例

Kafka生产与消费流程 Kafka是一款消息中间件&#xff0c;消息中间件本质就是收消息与发消息&#xff0c;所以这节课我们会从一条消息开始生产出发&#xff0c;去了解生产端的运行流程&#xff0c;然后简单的了解一下broker的存储流程&#xff0c;最后这条消息是如何被消费者消…

GNU Linux 的退出码规定

参考&#xff1a;https://tldp.org/LDP/abs/html/exitcodes.html 从这张表里来看&#xff0c;小于 128 的是被程序员捕捉的错误&#xff0c;大于等于 128 的是真正的 bugs &#xff1f;

MySQL卸载干净再重新安装【Windows】

家人们&#xff0c;谁懂啊&#xff1f; 上学期学的数据库&#xff0c;由于上学期不知道为什么抽风&#xff0c;过得十分的迷&#xff0c;上课跟老师步骤安装好了Mysql&#xff0c;但后面在使用的过程中出现了问题&#xff0c;而且还出现了忘记密码这么蠢的操作&#xff0c;后半…

linux设置登录超时自动退出

问题背景 最近登录某台linux服务器&#xff0c;经常遇到超时自动退出现象&#xff0c;如下图&#xff1a; 是因为服务器设置了超时时间&#xff0c;如果某个超时时间段内服务器没有任何操作&#xff0c;则会自动注销 解决方法 查看服务器设置的超时时间(TMOUT 变量的值)&am…

非科班菜鸡算法学习记录 | 代码随想录算法训练营第59天||503.下一个更大元素II 42. 接雨水

503. 下一个更大元素 II 知识点&#xff1a;单调栈 状态&#xff1a;不会&#xff0c;全靠卡哥 思路&#xff1a; 用i%nums.size()来代替i&#xff0c; 用for遍历时遍历两次 // 版本二 class Solution { public:vector<int> nextGreaterElements(vector<int>&am…

TLA+学习记录1——hello world

0x01 TLA是个好工具 编程人员一个好习惯是凡事都想偷懒&#xff0c;当然是指要科学地偷懒&#xff0c;而不是真的偷懒。一直想找到一种能检验写出的代码&#xff0c;做出的设计是否真的完全正确&#xff0c;而不是靠经验检视、代码Review、反复测试去检验。因为上述方法不管怎…

MATLAB中M文件编写

简介 所谓M文件就是将处理问题的各种命令融合到一个文件中&#xff0c;该文件以.m为扩展名。然后&#xff0c;由MATLAB系统编译M文件&#xff0c;得出相应的运行结果。M文件具有相当大的可开发性和扩展性。M文件有脚本文件和函数文件两种。脚本文件不需要输入参数&#xff0c;…

【美团3.18校招真题1】

大厂笔试真题网址&#xff1a;https://codefun2000.com/ 塔子哥刷题网站博客&#xff1a;https://blog.codefun2000.com/ 小美剪彩带 提交网址&#xff1a;https://codefun2000.com/p/P1088 题意&#xff1a;找出区间内不超过k种数字子数组的最大长度 使用双指针的方式&…

js使用crypto-js做加密解密

首先安装 crypto-js npm install crypto-js下面是完整代码&#xff0c;首先引入 crypto-js 里的 AES 和 enc&#xff0c;声明加密方法和解密方法进行测试 let { AES, enc } require("crypto-js");// 加密方法 function encryptString(str, key) {// 使用 AES 加密…

Unity Shader 溶解效果

一、效果图 二、原理分析 实现原理就是在片元着色器中&#xff0c;对像素点进行丢弃不显示。借助美术做的噪点图(利用噪点图中rgb中r值来做计算)。比如噪点图r值从0-1。我们从小到大让r值逐渐丢弃&#xff0c;比如刚开始r < 0.1丢弃&#xff0c;然后t < 0.2丢弃...知道t…