在 python 中调用 C/C++

news2024/9/20 10:31:57

Python 是一种很好用的胶水语言,利用Python的简洁和C++的高效,基本可以解决99%的问题了,剩下那 1% 的问题也就不是问题了,毕竟不是所有问题都可解。

一般的,Python和C++的交互分为这两种情况:

  • 用C++扩展Python:当一个Python项目中出现了性能瓶颈时,将瓶颈部分抽离出来,用C++封装成一个Python可以调用的模块(so库);
  • 将Python内嵌入C++:当一个C++项目中有部分功能预期将会经常变更需求,期望获得更高的灵活性时,将这部分功能用Python实现,在C++中进行调用。

这里讨论前者,在 python 中调用 C/C++ 代码的方法很多,这里记录三种方法的使用。

1 C/C++ 编译成可执行文件,python 通过 subprocess 调用

C/C++ 代码正常编写,然后编译成 exe/elf 格式的可执行文件,Python 利用 subprocess 调用该可执行文件即可。好处是改动小,不好是至少需要两个进程跑代码,而且 C/C++ 和 Python 通讯比较麻烦。

这种方法简单粗暴,不太好用,没什么好说的。

2 ctypes

C/C++ 在编写代码的时候略微改动,然后编译成 dll/so 格式的动态库文件,Python 利用 ctypes 调用该库文件即可。好处一个进程内运行,C/C++ 侧改动小,坏处是 Python 侧需适配代码比较多。

ctypes 是 python 自带的一个库,可以用来调用 c/cpp 的动态链接库。使用 ctypes 调用 c++ 代码步骤如下:

  • 编写 cpp 代码,将其编译成动态链接库(.so 或者 .dll 文件)。
  • 在 python 代码文件中导入 ctypes 库,并使用 ctypes.cdll.LoadLibrary() 方法加载动态链接库。
  • 使用 ctypes 定义 c++ 函数的参数类型和返回值类型,并调用 c++ 函数。
2.1 编译 C++

一个简单的 demo:
dll.cpp

extern "C" int add(int a, int b) {
	return a + b;
}

在目录 python_call_c_cpp 下,使用 g++ 编译 dll.cpp

g++ --shared -fPIC dll.cpp -o libadd.so

编译完成后,在目录下会生成一个 libadd.so 文件:

在这里插入图片描述

2.2 python 调用 C/C++ 库

main.py

import ctypes

# 加载动态链接库 
lib = ctypes.cdll.LoadLibrary("./libadd.so") 
# 定义函数参数类型和返回值类型 
lib.add.argtypes = [ctypes.c_int, ctypes.c_int] 
lib.add.restype = ctypes.c_int 

# 调用 C++ 函数 
result = lib.add(1, 2) 
print("调用C++库的结果:" + str(result))

执行 python3 main.py:

在这里插入图片描述

3 Boost.Python

Boost作为一个大宝库,提供了我们所需要的这一功能。并且,在Boost的许多库中,已经默认使用了Boost.Python,所以也算是经过了充分的测试。

3.1 安装

Boost的大部分功能都是以头文件的形式提供的,无需安装;但是也有少部分功能,需要进行手动编译。Boost.Python 需要进行手动编译。

3.2 一个简单的 demo

用C++实现一个模块,在Python中调用时,可以返回一个特定的字符串。

#include <boost/python.hpp>

char const* greet()
{
	return "hello, boost";
}

BOOST_PYTHON_MODULE(hello_boostpy)
{
	using namespace boost::python;
	def("greet", greet);
}

将其编译成动态链接库的形式:

g++ -I /usr/include/python2.7/ -fPIC -shared -o hello_boostpy.so http://hello_boostpy.cc -lboost_python

这时可以使用ldd看看hello_boostpy.so可不可以找到libboost_python,找不到的话,需要手动将其路径加入环境变量LD_LIBRARY_PATH中,或者用ldconfig相关的命令也可以。

在Python中使用hello_boostpy库:

# -*- coding: utf-8 -*-
import sys
sys.path.append('.')


def test():
    import hello_boostpy
    return hello_boostpy.greet()


if __name__ == "__main__":
    print test()

接下来,我们在C++实现的模块中,添加一个类,并且尝试向C++方向传入Python的list类型对象。
C++ 类:

#include <boost/python.hpp>
#include <vector>
#include <string>
#include <sstream>
using namespace boost::python;

struct Person
{
	void set_name(std::string name) { this->name = name; }
	std::string print_info();
	void set_items(list& prices, list& discounts);
	
	
	std::string name;
	std::vector<double> item_prices;
	std::vector<double> item_discounts;
};

其中,Python方的list类型,在Boost.Python中有一个对应的实现boost::python::list(相应的,dict、tuple等类型都有对应实现)。在set_items中,我们将会用boost::python::extract对数据类型做一个转换。

void Person::set_items(list& prices, list& discounts)
{
	for(int i = 0; i < len(prices); ++i)
	{
		double price = extract<double>(prices[i]);
		double discount = extract<double>(discounts[i]);
		item_prices.push_back(price);
		item_discounts.push_back(discount);
	}
}

Python模块定义部分依旧是非常直观的代码:

BOOST_PYTHON_MODULE(person)
{
	class_<Person>("Person")
		.def("set_name", &Person::set_name)
		.def("print_info", &Person::print_info)
		.def("set_items", &Person::set_items)
	;	
}

在Python代码中,就可以像使用一个Python定义的类一样使用Person类了:

# -*- coding: utf-8 -*-
import sys
sys.path.append('.')


def test():
    import person
    p = person.Person()
    p.set_name('Qie')
    p.set_items([100, 123.456, 888.8], [0.3, 0.1, 0.5])
    print p.print_info()


if __name__ == "__main__":
    test()

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

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

相关文章

标准化编程系列(常用模式状态介绍)

任何事情任何编程都是有方法可循的,我们所要做的工作就是在看似没有规律的运行中,发现规律总结一般性的方法。这篇博客主要介绍标准化编程相关的基础知识,编程化编程离不开大家扎实的编程基本功,所以在学习标准化的同时,大家需要提升对于子程序,模块FB 、FC等的应用知识,…

Windows11通过Hyper-V创建VM,然后通过vscode连接vm进行开发

这边需要在win11上建立vm来部署docker(这边不能用windows版本的docker destop)&#xff0c;学习了下&#xff0c;记录。 下载系统镜像 首先下载系统镜像&#xff1a;https://releases.ubuntu.com/focal/ 这边使用的是ubuntu20.04.6 LTS (Focal Fossa) &#xff0c;Server inst…

D4800——AB类立体声耳机放大芯片, 输出电压振幅大,电源抑制比好且低功耗, 工作温度范围宽 无开关噪声

D4800是一块AB类立体声耳机音频功率放大器电路。D480在5V电源时输出功率最高可290mW(89负裁失真度1090.适合在便携式数字音响设备中作功率放大用。 主要特点&#xff1a; ● 电源电压:单电源: 2V to 7V 双电源:1.0V to3.5V ● 高信噪比: 100dB DIP8. ● 转速快: 5V/us ● 失…

【乳腺肿瘤诊断分类及预测】基于PNN概率神经网络

课题名称&#xff1a;基于PNN的乳腺肿瘤诊断分类及预测 版本日期&#xff1a;2023-06-15 运行方式: 直接运行PNN0501.m 文件即可 代码获取方式&#xff1a;私信博主或QQ&#xff1a;491052175 模型描述&#xff1a; 威斯康辛大学医学院经过多年的收集和整理&#xff0c;建…

关于Spring框架的 @Configuration 与@Service 加载顺序哪个先后(某些环境加载是随机的)

很多资料都说Configuration 优先加载&#xff0c;Service后加载&#xff0c;如下图&#xff1a; 本来也是以为 Configuration 优先加载于 Service &#xff0c;那参数处理放在Configuration注入完后&#xff0c;service构建时就可以拿来用的&#xff0c;在我在IDEA的调试时下断…

【蓝桥杯日记】复盘篇三——循环结构

前言 本篇内容是对循环结构进行复盘的&#xff0c;循环可谓是在基础阶段特别重要的东西&#xff0c;是三大结构&#xff08;顺序结构、选择结构、循环结构&#xff09;中最重要的结构之一。 目录 &#x1f351;1.找最小值 分析&#xff1a; 知识点&#xff1a; 代码如下 &…

【C/Python】Gtk部件ListStore的使用

一、C语言 在GTK中&#xff0c;Gtk.ListStore是一个实现了Gtk.TreeModel接口的存储模型&#xff0c;用于在如Gtk.TreeView这样的控件中存储数据。以下是一个简单的使用Gtk.ListStore的C语言示例&#xff0c;该示例创建了一个列表&#xff0c;并在图形界面中显示&#xff1a; …

PostGIS教程学习二十二:使用触发器追踪历史编辑操作

PostGIS教程学习二十二&#xff1a;使用触发器追踪历史编辑操作 生产环境下数据库的一个常见要求是能够跟踪用户编辑数据的历史&#xff1a;数据在两个日期之间是如何变化的&#xff0c;是谁操作的&#xff0c;以及它们哪些内容变化了&#xff1f;一些GIS系统通过在客户端接口…

单片机学习笔记--- 定时器/计数器(简述版!)

目录 定时器的介绍 定时计数器的定时原理 定时计数器的内部结构 两种控制寄存器 &#xff08;1&#xff09;工作方式寄存器TMOD &#xff08;2&#xff09;控制寄存器TCON 定时计数器的工作方式 方式0 方式1 方式2 方式3 定时器的配置步骤 第一步&#xff0c;对…

go语言socket编程

1.互联网分层模型 过程分析&#xff1a; 2.Socket图解 Socket是应用层与TCP/IP协议族通信的中间软件抽象层。在设计模式中&#xff0c;Socket其实就是一个门面模式&#xff0c;它把复杂的TCP/IP协议族隐藏在Socket后面&#xff0c;对用户来说只需要调用Socket规定的相关函数&a…

【笔记】React-Native跟Android交互--简单示例

/** * 使用命令 npx react-nativelatest init DemoRN创建项目 * * "react": "18.2.0", * "react-native": "0.73.2" * * 官网有详细教程&#xff1a;https://reactnative.dev/docs/native-modules-android */ 一、RN invoke androi…

【Oracle云】使用 boto3 访问 OCI 对象存储 (AWS S3协议兼容)

在现代云计算环境中&#xff0c;S3&#xff08;Simple Storage Service&#xff09;协议已经成为云对象存储的事实标准。它提供了简单、可扩展、高度耐用的存储解决方案&#xff0c;得到了广泛应用。Oracle Cloud Infrastructure&#xff08;OCI&#xff09;秉承着开放性和灵活…

ArcGIS Pro字段编号相关代码

字段属于SHP文件的重要组成部分&#xff0c;在某些时候需要对字段进行编号&#xff0c;这里为大家介绍一下字段编号相关的代码&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微图中下载的POI数据&#xff0c;除了POI数据&#xff0c;常见的GIS数据都可…

zookeeper(2) 服务器动态上下线监听和分布式锁案例

案例一&#xff1a;服务器动态上下线监听 某分布式系统中&#xff0c;主节点可以有多台&#xff0c;可以动态上下线&#xff0c;任意一台客户端都能实时感知 到主节点服务器的上下线。 1.服务端代码 package com.atguigu.case1;import org.apache.zookeeper.*;import java.io…

【大厂AI课学习笔记】1.3 人工智能产业发展(3)

1.3.1 供给侧 技术层面&#xff1a;从实验室走向大规模的商用。 数据层面&#xff1a;数据正式成为重要的生产要素。 市场&#xff1a;供需互促的正向市场环境建立。 资本&#xff1a;走出炒作泡沫&#xff0c;聚焦价值领域。 平台&#xff1a;大厂普遍开放生态。 MORE&am…

Java:搭建eladmin复习mvn、springboot、vue等

目录 1.源码平台后端&#xff1a; 2.源码平台前端&#xff1a; 3.操作系统&#xff1a;centos7.9 4.mysql:5.7.x 安装 5.redis:5.0.X 6.maven&#xff1a;3.8 7.java:1.8&#xff1a; 8.nodejs:16.x 9.通过mvn打包eladmin后端 10.npm打包前端项目进行部署 11.访问测试…

【GEE】基于GEE批量下载Landsat8 L2A数据(整幅)

之前发过一篇使用GEE下载Landsat8的文章&#xff0c;然后有很多小伙伴私信我各种问题&#xff0c;如L1C、L2数据代码怎么修改&#xff0c;如何镶嵌&#xff0c;如何去云、 如何裁剪等一系列问题。正好快过年了&#xff0c;手头的事也没有多少了&#xff0c;所以这两天整理了一下…

ElementUI Form:InputNumber 计数器

ElementUI安装与使用指南 InputNumber 计数器 点击下载learnelementuispringboot项目源码 效果图 el-radio.vue &#xff08;InputNumber 计数器&#xff09;页面效果图 项目里el-input-number.vue代码 <script> export default {name: el_input_number,data() {re…

Log4j2-29-log4j2 discard policy 极端情况下的丢弃策略 同步+异步配置的例子

Log4j2异步日志、同步日志和混合日志的配置详解 Log4j 2中记录日志的方式有同步日志和异步日志两种方式&#xff0c;其中异步日志又可分为使用AsyncAppender和使用AsyncLogger两种方式。 异步日志(性能最好&#xff0c;推荐使用) 异步日志情况下&#xff0c;增加 Disruptor …

如何用JAVA代码将视频号视频下载到本地

1、目前只掌握了&#xff0c;下载自己视频号后台的视频的方法&#xff1a; 登录视频号助手网页-点开视频-复制链接-&#xff08;I/O&#xff09;下载 代码如下&#xff1a; String videoUrl "xxx";String savePath "D:\\videoDownload\\video.mp4";tr…