C/C++调用python

python环境

通过如下的命令,可以获取到当前python环境下对应的路径。比如程序编译需要指定对应的头文件、库文件路径,链接阶段需要指定需要链接哪些库。

# 说明python3-config支持哪些选项
$ python3-config 
Usage: /home/yangye/miniconda3/bin/python3-config --prefix|--exec-prefix|--includes|--libs|--cflags|--ldflags|--extension-suffix|--help|--abiflags|--configdir|--embed$ python3-config --prefix
/home/yangye/miniconda3
# 对应的头文件路径
$ python3-config --includes
-I/home/yangye/miniconda3/include/python3.10 -I/home/yangye/miniconda3/include/python3.10
# 对于python3.8 以下通过--libs可以获取对应的链接库名称
$ python3-config --libs-lcrypt -lpthread -ldl  -lutil -lm -lm 
# python3.8以上需要加上--embed
$ python3-config --libs --embed
-lpython3.10 -lcrypt -lpthread -ldl  -lutil -lm -lm $ python3-config --cflags
-I/home/yangye/miniconda3/include/python3.10 -I/home/yangye/miniconda3/include/python3.10  -Wno-unused-result -Wsign-compare -march=nocona -mtune=haswell -ftree-vectorize -fPIC -fstack-protector-strong -fno-plt -O3 -ffunction-sections -pipe -isystem /home/yangye/miniconda3/include -fdebug-prefix-map=/croot/python-split_1679423815169/work=/usr/local/src/conda/python-3.10.10 -fdebug-prefix-map=/home/yangye/miniconda3=/usr/local/src/conda-prefix -fuse-linker-plugin -ffat-lto-objects -flto-partition=none -flto -DNDEBUG -fwrapv -O3 -Wall
# 对应的库文件路径
$ python3-config --ldflags
-L/home/yangye/miniconda3/lib/python3.10/config-3.10-x86_64-linux-gnu -L/home/yangye/miniconda3/lib  -lcrypt -lpthread -ldl  -lutil -lm -lm $ python3-config --extension-suffix.cpython-310-x86_64-linux-gnu.so
$ python3-config --abiflags$ python3-config --configdir
/home/yangye/miniconda3/lib/python3.10/config-3.10-x86_64-linux-gnu

编译动态库

python支持将一个模块编译成动态库,然后对动态库进行调用,与import模块的效果一样。下面是一个简单的例子,说明编译动态库的过程。

  1. 安装Cython
 pip install Cython
  1. 编写python模块
def hello(s):print(s)
  1. 编写setup.py文件
from distutils.core import setup
from Cython.Build import cythonizesetup(name = "sharedModule",ext_modules= cythonize("sharedModule.py")
)
  1. 编译
python setup.py build_ext --inplace

C++调用Python

本文重点是介绍如何使用C/C++调用python程序,具体实现代码参考了如下文章。C语言调用Python脚本的原理主要基于Python提供的C API。Python的C API允许C语言程序调用Python解释器,并进行交互操作,如执行Python代码、调用Python函数等。
C++使用Python/C API_c++ 调用api_Eliza_Her的博客-CSDN博客

CMake

下面是一个CMake编译对应的CMakeFiles.txt文件内容,具体可以执行定义的命令替换相应的路径。

cmake_minimum_required(VERSION 3.19)
project(cppCallPythonFunc)#set(CMAKE_CXX_STANDARD 14)
# python3-config --includes
include_directories("/home/xxxx/miniconda3/include/python3.10"
)#在控制台运行python3.6-config --ldflags 取得参数
#-L/usr/lib/python3.6/config-3.6m-x86_64-linux-gnu -L/usr/lib -lpython3.6m -lpthread -ldl  -lutil -lm  -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions# 添加动态库的位置
LINK_DIRECTORIES("/home/xxxx/miniconda3/lib/python3.10/config-3.10-x86_64-linux-gnu" "/home/xxxx/miniconda3/lib")
# LINK_DIRECTORIES("/usr/lib")add_executable(main main.cpp)
target_link_libraries(main -lpython3.10 -lcrypt -lpthread -ldl  -lutil -lm )

调用python

C/C++调用Python脚本的基本步骤:

  1. 初始化Python解释器:使用Py_Initialize()函数,这是调用Python脚本之前必须的步骤。
  2. 调用Python代码:可以使用PyRun_SimpleString()函数执行Python代码,或者使用PyImport_ImportModule()函数导入Python模块。
  3. 获取并调用Python函数:首先,可以使用PyObject_GetAttrString()或者PyObject_GetAttr()获取Python对象(例如,模块或类)的属性(例如,函数)。然后,可以使用PyObject_CallObject()PyObject_CallFunction()调用获取到的Python函数。
  4. 处理Python函数的返回值:可以使用Python的C API提供的函数来获取和处理Python函数的返回值。
  5. 释放资源并关闭Python解释器:使用Py_Finalize()函数。

直接运行python代码段

#include <Python.h>
#include <iostream>
using namespace std;int main(int argc, char *argv[]) 
{// 初始化python解释器.C/C++中调用Python之前必须先初始化解释器Py_Initialize();if(Py_IsInitialized()){std::cout << "python translator initialized." << std::endl;}// 执行一个简单的执行python脚本命令PyRun_SimpleString("print('hello world')\n");// 撤销Py_Initialize()和随后使用Python/C API函数进行的所有初始化// 并销毁自上次调用Py_Initialize()以来创建并为被销毁的所有子解释器。Py_Finalize();return 0;
}

直接运行python脚本

#include <Python.h>
#include <iostream>
using namespace std;int main(int argc, char *argv[]) 
{// 初始化python解释器.C/C++中调用Python之前必须先初始化解释器Py_Initialize();if(Py_IsInitialized()){std::cout << "python translator initialized." << std::endl;}// 运行python脚本PyRun_SimpleString("import sys");PyRun_SimpleString("sys.path.append('..')");// 输入python脚本文件名string filename = "../simple_run.py";PyObject* obj = Py_BuildValue("s", filename.c_str());FILE* file = _Py_fopen_obj(obj, "r+");if (file != NULL){PyRun_SimpleFile(file, filename.c_str());}// 撤销Py_Initialize()和随后使用Python/C API函数进行的所有初始化// 并销毁自上次调用Py_Initialize()以来创建并为被销毁的所有子解释器。Py_Finalize();return 0;
}

导入python模块,调用python函数

解析参数并构建值变量
如何将二维数组从C语言传递到Python?
C调用Python(传递数字、字符串、list数组(一维、二维),结构体)_c++与python 传递数组-CSDN博客
https://docs.python.org/3/c-api/index.html
以下代码是Py_BuildValue函数构建不同类型的数据,作为python函数的输入,可以做一个参考。

Py_BuildValue("") None
Py_BuildValue("i", 123) 123
Py_BuildValue("iii", 123, 456, 789) (123, 456, 789)
Py_BuildValue("s", "hello") 'hello'
Py_BuildValue("ss", "hello", "world") ('hello', 'world')
Py_BuildValue("s#", "hello", 4) 'hell'
Py_BuildValue("()") ()
Py_BuildValue("(i)", 123) (123,) 
Py_BuildValue("(ii)", 123, 456) (123, 456)
Py_BuildValue("(i,i)", 123, 456) (123, 456)
Py_BuildValue("[i,i]", 123, 456) [123, 456] Py_BuildValue("{s:i,s:i}", "abc", 123, "def", 456) {'abc': 123, 'def': 456}
Py_BuildValue("((ii)(ii)) (ii)", 1, 2, 3, 4, 5, 6) (((1, 2), (3, 4)), (5, 6))

以下是一个简单的python模块,定义了三种函数,无参数,简单类型的参数和list参数输入。

import time
import numpy as np
import torch
import cv2def print_time():print(f"now {time.ctime()}")def add_num(a, b):print(np.__version__)print(torch.__version__)print(cv2.__version__)return a + bdef test_lst(lst):print(lst)

下面是具体的C++代码实现,导入文件的模块,然后调用其中的函数内容。测试list有好多坑呀。

#include <Python.h>
#include <iostream>
using namespace std;int main(int argc, char *argv[]) 
{// 初始化python解释器.C/C++中调用Python之前必须先初始化解释器Py_Initialize();if(Py_IsInitialized()){std::cout << "python translator initialized." << std::endl;}PyRun_SimpleString("import sys");PyRun_SimpleString("sys.path.append('..')");PyObject* pModule = NULL;PyObject* pFunc = NULL;PyObject* args = NULL;//import模块pModule = PyImport_ImportModule("simple_module");//模块文件名//找不到模块则报错if (pModule == nullptr) {PyErr_Print();Py_Finalize();return 0;}//1. 调用不带参数的函数 Hello()pFunc = PyObject_GetAttrString(pModule, "print_time");//函数名PyObject_CallFunction(pFunc, NULL);//调用函数//2. 调用带参数的函数 Add(a, b)pFunc = PyObject_GetAttrString(pModule, "add_num");args = Py_BuildValue("(ii)", 123, 456); //设置传入Add的参数PyObject* pRet = PyObject_CallObject(pFunc, args); //pRet = Add(123, 456)// 3. 解析返回值int ans = 0;PyArg_Parse(pRet, "i", &ans);	//返回类型转换printf("Return C++: ans = %d\n", ans);// 测试一维数组double CArray[] = {1.2, 4.5, 6.7, 8.9, 1.5, 0.5};PyObject *PyList  = PyList_New(6);PyObject *ArgList = PyTuple_New(1);for(int i = 0; i < PyList_Size(PyList); i++)PyList_SetItem(PyList,i, PyFloat_FromDouble(CArray[i]));//给PyList对象的每个元素赋值PyTuple_SetItem(ArgList, 0, PyList);//将PyList对象放入PyTuple对象中pFunc = PyObject_GetAttrString(pModule, "test_lst");//函数名PyObject_CallObject(pFunc, ArgList);//调用函数,完成传递// 撤销Py_Initialize()和随后使用Python/C API函数进行的所有初始化// 并销毁自上次调用Py_Initialize()以来创建并为被销毁的所有子解释器。Py_Finalize();return 0;
}

调用python类

python中类的使用比较普遍,下面重点介绍一下如何导入python类,并访问对应的属性和方法,具体参考了如下文章。
【精选】C调用python类的正确方法-CSDN博客
下面的代码定义了一个类,并导入了深度学习中常用的库作为测试,并测试了list作为输入的情况。

import numpy as np
import torch
import cv2class myClass:welcome = "Hello from Python class attribute"def hello(self):print(np.__version__)print(torch.__version__)print(cv2.__version__)print("Hello from Python class method")def minus(self, a, b):print(str(a) + " - " + str(b) + " = " + str(a-b))return a-bdef print_lst(self, lst):print(lst)

以下是对应的C++代码,具体可以参考注释。

#include <Python.h>
#include <iostream>
using namespace std;int main(int argc, char *argv[]) 
{// 初始化python解释器.C/C++中调用Python之前必须先初始化解释器Py_Initialize();if(Py_IsInitialized()){std::cout << "python translator initialized." << std::endl;}PyRun_SimpleString("import sys");PyRun_SimpleString("sys.path.append('..')");PyObject* pModule = NULL;PyObject* pFunc = NULL;PyObject* args = NULL;//import模块pModule = PyImport_ImportModule("simple_class");//模块文件名//找不到模块则报错if (pModule == nullptr) {PyErr_Print();Py_Finalize();return 0;}// 模块的字典列表PyObject* pDict = PyModule_GetDict(pModule);if (!pDict) {PyErr_Print();Py_Finalize();return 0;}//从字典中获取myClass类PyObject* pClassCalc = PyDict_GetItemString(pDict, "myClass");if (!pClassCalc) {PyErr_Print();Py_Finalize();return 0;}// 获取构造函数PyObject* pConstruct = PyInstanceMethod_New(pClassCalc);if (!pConstruct) {PyErr_Print();Py_Finalize();return 0;}// 调用构造函数 构建对象PyObject* pIns = PyObject_CallObject(pConstruct,nullptr);//获取pIns实例的属性,转换成字符串并输出PyObject* obj2 = PyObject_GetAttrString(pIns, "welcome");PyObject* str = PyUnicode_AsEncodedString(obj2, "utf-8", "strict");char* result = PyBytes_AsString(str);printf("%s\n", result);//如果属性是int型,可用下面这句转换属性://int qwq;//PyArg_Parse(obj2, "i", &qwq);// args = Py_BuildValue("(ii)", 123, 456); //设置传入Add的参数args = PyTuple_New(2);PyTuple_SET_ITEM(args, 0, Py_BuildValue("i", 1));PyTuple_SET_ITEM(args, 1, Py_BuildValue("i", 2));PyObject_CallMethod(pIns, "print_lst", "(O)", args);//调用无参数Python方法PyObject_CallMethod(pIns, "hello", nullptr);//调用多参数Python方法PyObject* pRet = PyObject_CallMethod(pIns, "minus","(i,i)", 12, 22);if (!pRet){PyErr_Print();Py_Finalize();return 0;}int res = 0;PyArg_Parse(pRet, "i", &res);//转换返回类型printf("Return C++: ans = %d\n", res);// 撤销Py_Initialize()和随后使用Python/C API函数进行的所有初始化// 并销毁自上次调用Py_Initialize()以来创建并为被销毁的所有子解释器。Py_Finalize();return 0;
}

从动态库中导入python模块

参考第二小节:编译动态库,得到动态库,将其拷贝到main.cpp的同级目录下,此时可以以动态库的形式加载python模块,后续使用和之前文件一样。
项目的整体文件结构如下:

.
├── [ 761]  CMakeLists.txt
├── [ 13K]  main
├── [2.3K]  main.cpp
├── [ 57K]  simple_class.cpython-310-x86_64-linux-gnu.so
├── [ 102]  simple_module.py
├── [ 113]  simple_run.py
└── [4.0K]  test_shared├── [4.0K]  build│   ├── [4.0K]  lib.linux-x86_64-cpython-310│   │   └── [ 57K]  simple_class.cpython-310-x86_64-linux-gnu.so│   └── [4.0K]  temp.linux-x86_64-cpython-310│       └── [ 56K]  simple_class.o├── [ 150]  setup.py├── [269K]  simple_class.c├── [ 57K]  simple_class.cpython-310-x86_64-linux-gnu.so└── [ 241]  simple_class.py

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

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

相关文章

ESP32 Arduino实战基础篇-使用中断和定时器

本教程介绍如何使用 PIR 运动传感器通过 ESP32 检测运动。在此示例中,当检测到运动(触发中断)时,ESP32 会启动计时器并打开 LED 并持续预定义的秒数。当计时器倒计时结束时,LED 自动关闭。 通过这个例子,我们还将探讨两个重要的概念:中断和定时器。 中断介绍 要使用 P…

【MySQL】表的增删改查(基础)

一、新增&#xff08;Create&#xff09; 先创建一张表&#xff1a; create table student (id int,sn int comment 学号,name varchar(20),email varchar(20));1.1 单行数据 全列插入 插入两条记录&#xff0c;value_list 数量必须和定义表的列的数量及顺序一致 insert i…

BeanUtils中的copyProperties方法使用

一、Beanutils中的copyProperties是我们在日常开发中常用的一个方法。 作用&#xff1a; 将a实体类中的属性赋值到b实体类中相对于的字段上 1.我们前端传参的时候我们后端通常会用vo实体类来接收&#xff0c;但是更新数据库的时候需要用do去操作 2.我们将vo的属性copy到do中可…

How to design a database storage model for water network information system

How to design a database storage model for water network information system 1、领域划分2、基础域2.1、概述2.2、E-R图2.3、SQL脚本 1、领域划分 序号中文名称英文名称代号备注1基础域basea012资产域assertsa023监测域monitora034水权域quotaa045灌溉域irrigationa056排涝…

HIGG FEM4.0即将实行

【HIGG FEM4.0即将实行】 01主要问题数量‍ 首先是主要问题的数量&#xff0c;为了与行业内的新倡议、新标准保持一致&#xff0c;对原有的各个板块的问题进行了一定的改善&#xff0c;FEM 4.0中涉及到的问题数量比3.0版本新增了一些&#xff0c;但并不是所有的问题都需要回答&…

矿区安全检查VR模拟仿真培训系统更全面、生动有效

矿山企业岗位基数大&#xff0c;生产过程中会持续有新入矿的施工人员及不定期接待的参观人员&#xff0c;下井安全须知培训需求量大。传统实景拍摄的视频剪辑表达方式有限&#xff0c;拍摄机位受限&#xff0c;难以生动表达安全须知的内容&#xff0c;且井下现场拍摄光线不理想…

三菱FX3U小项目—自锁控制与故障报警

目录 一、项目描述 二、IO口分配 三、项目程序 四、总结 一、项目描述 当按下启动按钮时&#xff0c;电机通电运转&#xff0c;当按下停止按钮时&#xff0c;电动机断电停止&#xff1b;当设备检修旋钮得电时&#xff0c;电动机停止并且故障指示灯闪烁1s&#xff1b;当电动…

【PyQt小知识 - 4】:QGroupBox分组框控件 - 边框和标题设置

QGroupBox QGroupBox 是 PyQt 中的一个小部件&#xff0c;用于创建一个带有标题的组框。 可以使用 QGroupBox 将相关控件分组并添加一个标题。 以下是一个使用 QGroupBox 的示例代码&#xff08;示例一&#xff09;&#xff1a; from PyQt5.QtWidgets import * import sysa…

【MySql】12- 实践篇(十)

文章目录 1. 为什么临时表可以重名?1.1 临时表的特性1.2 临时表的应用1.3 为什么临时表可以重名&#xff1f;1.4 临时表和主备复制 2. MySql内部临时表使用场景2.1 union 执行流程2.2 group by 执行流程2.3 group by 优化方法 -- 索引2.4 group by 优化方法 -- 直接排序 3. Me…

SWT 中实现最小化到托盘图标,并只能通过托盘的弹出菜单关闭程序

SWT 3.0 开始引入了 Tray&#xff0c;可以在系统栏放置你的程序图标了 本程序实现的功能有&#xff1a; 点击窗口的最小化或关闭按钮都是隐藏窗口–任务栏里不显示&#xff0c;不退出程序窗口隐藏时&#xff0c;任务栏无图标&#xff0c;系统栏有图标&#xff1b;窗口处于显示…

【第2章 Node.js基础】2.7 Node.js 的流(一)可写流

&#x1f308;可写流 &#x1f680;什么是可写流 可写流是对数据被写入的目的地的一种抽象。 所有可写流都实现了 stream.Writable类定义的接口。 可写流的例子包括&#xff0c;也都是实现了可写流接口的双工流 客户端的 HTTP 请求、服务器的HTTP 响应、fs 的写入流、zlib…

【第2章 Node.js基础】2.6 Node.js 的Buffer数据类型

Buffer数据类型 文章目录 Buffer数据类型什么是Buffer数据类型Buffer 的特点 创建Buffer实例Buffer用于编码转换将Buffer 实例转换为JSON 对象Buffer实例基本操作1. 写入Buffer实例&#xff1a;2. 从Buffer实例读取数据&#xff1a;3. Buffer实例合并&#xff1a; 4. Buffer实例…

Android Jetpack的组件介绍,常见组件解析

jetpack组件有哪些 Android Jetpack是一个集成Android应用程序组件的一站式解决方案。它使开发人员能够专注于他们的应用程序的真正创新部分&#xff0c;而不会受到Android平台特定的限制。Jetpack组件可分为四个类别&#xff1a; 架构组件&#xff08;Architecture Componen…

从流程优化到经营提效,法大大电子签全面助力智慧零售升级

在新零售模式下&#xff0c;“商业综合体、百货商场、连锁商超、连锁便利店、线上电商平台”等各类商业零售企业借助数字化的手段来改造和重塑传统零售流程和逻辑&#xff0c;实现全面数字化转型&#xff0c;包括线上线下一体化、全场景覆盖、全链条联通、全渠道经营、客户服务…

【ASP.NET】Hello World

文章目录 1. 几个概念2. 搭建开发环境2.1 .NET SDK2.2 IDE & Editor 3 First Project3.1 步骤3.2 模板3.3 项目结构3.4 请求的处理流程 Reference Link 1. 几个概念 .NET 是一个平台&#xff0c;包括 .NET Framework、.NET Core、ASP.NET、C#等&#xff0c;可以构建桌面、W…

【python】Django——连接mysql数据库

笔记为自我总结整理的学习笔记&#xff0c;若有错误欢迎指出哟~ 【Django专栏】 Django——django简介、django安装、创建项目、快速上手 Django——templates模板、静态文件、django模板语法、请求和响应 Django——连接mysql数据库 Django——连接mysql数据库 连接MySQL数据库…

ddrnet 分割学习笔记

目录 修改后可以加载预训练: 训练自己的数据代码: 默认分割后特征下采样8倍,最后用上采样恢复到原图; 修改后可以加载预训练: import math import torch import numpy as np import torch.nn as nn import torch.nn.functional as F from torch.nn import init from …

2023双十一爆冷收场,订单后暗藏这些电商痛点问题需要注意

打开某软件的瞬间&#xff0c;手不小心抖一下就进入了淘宝&#xff0c;而且无法第一时间准确找到关闭按钮。相信不少人都在这个双十一通过开屏广告为淘宝“贡献”至“超8亿”的访问量&#xff0c;更有网友辣评&#xff1a;“现在打开别的软件跳转淘宝的速度都比直接打开淘宝要快…

基于STM32婴儿床检测控制系统及源程序

一、系统方案 1、本设计采用STM32单片机作为主控器。 2、DHT11检测湿度&#xff0c;液晶OLED显示&#xff0c;声音检测声音&#xff0c;有声音或尿床&#xff0c;蜂鸣器报警。 3、手机APP可以控制音乐播放。 二、硬件设计 原理图如下&#xff1a; 三、单片机软件设计 1、首先…

新能源充电桩物联网应用之工业4G路由器

新能源充电桩是智慧城市建设中不可缺少且可持续发展的重要设施&#xff0c;而工业4G路由器物联网应用为其提供了更加高效、智能、实时的管理方式。充电桩通过工业4G路由器可以与充电运营商的管理中心建立稳定的连接&#xff0c;实现双向数据传输&#xff0c;为用户提供优质的充…