在 python 中调用 C/C++

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_boostpyreturn 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 personp = 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.hqwc.cn/news/444489.html

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

相关文章

【开源】SpringBoot框架开发海南旅游景点推荐系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用户端2.2 管理员端 三、系统展示四、核心代码4.1 随机景点推荐4.2 景点评价4.3 协同推荐算法4.4 网站登录4.5 查询景点美食 五、免责说明 一、摘要 1.1 项目介绍 基于VueSpringBootMySQL的海南旅游推荐系统&#xff…

AI的安全应答之道

作者&#xff1a;统信UOS技术团队 2023,随着各种大语言模型的爆发&#xff0c;整个AI生态正处于从决策式AI进化到生成式AI的进程中。各类AI模型和AI应用层出不穷&#xff0c;也随之带来了与AI相关的各类潜在风险。AI开发和使用过程中的风险防范和治理&#xff0c;成为了不可忽…

中国传媒网CEO徐晓艺荣膺第九届金鸥奖“2023年度最佳创新人物”殊荣

2023年是不平凡的一年,风云变幻。大国经济有韧性,离不开顶层设计、宏观政策的指挥,也离不开千百万求新求变的企业和企业家们的辛勤耕耘。在经历了三年疫情严峻考验的当下,中国号巨轮迎风搏浪心如磐石,无惧险阻屹立潮头,这不仅是中国红的底色,也是中国企业家的坚守和倔强。2023年…

linux+rv1126/imx6ull:opencv静态库交叉编译

目录 1.下载 2.准备工作 2.1安装依赖环境 2.2安装Cmake 2.3 解压opencv 3.Cmake设置 3.1文件夹选择 1&#xff09;进入源码根目录 2&#xff09;运行cmake 3&#xff09;选择目录 4&#xff09;进入配置界面 5&#xff09;查找编译器 6&#xff09;配置编译器 3.…

开源模型应用落地-业务优化篇(三)

一、前言 假如您跟随我的脚步&#xff0c;学习到上一篇的内容&#xff0c;到这里&#xff0c;相信细心的您&#xff0c;已经发现了&#xff0c;在上一篇中遗留的问题。那就是IM服务过载的时候&#xff0c;如何进行水平扩容&#xff1f; 因为在每个IM服务中&#xff0c;我们用JV…

MySQL数据控制语言DCL

MySQL数据控制语言DCL 目录 MySQL数据控制语言DCLDCL关键字1.事务事务的四大特性START TRANSACTION&#xff1a;开始事务ROLLBACK&#xff1a;回滚COMMIT&#xff1a;提交事务 2.用户权限CREATE USER&#xff1a;创建新的用户并指定权限DROP USER&#xff1a;删除用户ALTER USE…

RHCE DNS域名解析服务器

目录 1. 正向解析 1.1 安装必要软件 1.2 配置静态ip 1.3 DNS配置 1.4 测试 2. 反向解析 2.1 关闭安全软件&#xff0c;安装必要软件 2.2 配置静态ip 2.3 DNS配置 2.4 测试 1. 正向解析 1.1 安装必要软件 1.2 配置静态ip 服务器配置 nmcli c modify ens32 ipv4.method man…

【JavaSE】抽象类与接口

一、抽象类 在面向对象的概念中&#xff0c;所有的对象都是通过类来描绘的&#xff0c;但是反过来&#xff0c;并不是所有的类都是用来描绘对象的&#xff0c;如果一个类中没有包含足够的信息来描绘一个具体的对象&#xff0c;这样的类就是抽象类 我们把没有实际工作的方法设…

跟着cherno手搓游戏引擎【16】Camera和Uniform变量的封装

相机封装&#xff1a; OrthographicCamera.h: #pragma once #include <glm/glm.hpp> namespace YOTO {class OrthographicCamera{public:OrthographicCamera(float left,float right , float bottom,float top);const glm::vec3& GetPosition()const { return m_Pos…

1.26囚徒困境(单次,多次(有限次数,无限次数)),四种策略(netlogo建模最优,利益矩阵)

单次囚徒困境 转为奖励性矩阵就是说&#xff0c;被判时间越长那么奖励越少&#xff0c;反之奖励越多 有限次数博弈 就是说最后一次了&#xff0c;就随便破罐子破摔&#xff0c;不再继续合作&#xff0c;直接选择自己利益最大化了&#xff0c;如果有方式可以使其在原来、之前的…

SpringMVC-基本概念

一、引子 我们在上篇文章Spring集成Web中抛出了一个问题&#xff1a;为什么我们一直在自用Java Web阶段使用的Servlet来承接客户端浏览器的请求呢&#xff0c;我们熟知甚至是已经在日常开发中经常使用的Controller又与之有什么关系呢&#xff1f;我们将在本篇文章解答读者的这…

盲盒小程序开发,小程序带来的优势

我国盲盒行业的产品主要是以手办、公仔、动漫周边等为主&#xff0c;与各类知名IP合作推出的盲盒产品引起了年轻人的兴趣&#xff0c;盲盒市场得到了快速发展。目前&#xff0c;我国盲盒行业已经进入了蓬勃发展时期&#xff0c;商业机遇较多&#xff01; 在互联网时代下&#…