ctypes与numpy.ctypeslib的使用
numpy ctypeslib 与 ctypes接口使用说明
作者:elfin
使用numpy.ctypelib或者ctypes库可以实现python直接待用C++。numpy.ctypeslib后端是基于ctypes实现的!所以接口是类似的。
如果只想看如何调用外部接口可以直接查看 1.4.3.1 动态链接库使用成功案例,其他部分有很多试错的过程!
一、numpy.ctypeslib使用说明
numpy是python做计算非常基础的一个库,安装就直接使用pip install numpy即可。
导入python包:import numpy.ctypeslib as ctl
1.1 准备好一个C++计算文件
#include <iostream>
using namespace std;
int Paritition1(int A[], int low, int high) {
int pivot = A[low];
while (low < high) {
while (low < high && A[high] >= pivot) {
--high;
}
A[low] = A[high];
while (low < high && A[low] <= pivot) {
++low;
}
A[high] = A[low];
}
A[low] = pivot;
return low;
}
void QuickSort(int A[], int low, int high) //快排母函数
{
if (low < high) {
int pivot = Paritition1(A, low, high);
QuickSort(A, low, pivot - 1);
QuickSort(A, pivot + 1, high);
}
}
int main()
{
int arr[5] = { 9, 2, 8, -6, 5 };
QuickSort(arr, 0, 4);
for (int i = 0; i < 4; i++)
{
cout << arr[i] << " ";
}
cout << arr[4] << endl;
}
上面是一段C++版的快排代码。假设我们已经有这个cpp文件,那么如何在python中使用?
需要独立编译时,Windows系统可以在头文件中使用下面的语句
// __declspec(dllexport) 导出到库中(win系统环境下.dll文件链接宏)
extern "C" __declspec(dllexport) void QuickSort(int A[], int low, int high);
在Linux中需要使用extern进行声明
1.2 ctypeslib主要的五个接口
ctypeslib给我们提供了五个接口使用:
load_library加载c++文件;ndpointerc_intpas_ctypesnumpy数据类型转为ctypes类型as_arrayc++数据转为numpy数据类型
1.3 加载编译后的文件
我这里是在Windows上面测试,生成exe文件后可以直接读入。
c_quick = ctl.load_library(
libname="quick.exe",
loader_path=r"H:\quick\x64\Debug"
)
查看c_quick类型可以发现它是一个<class 'ctypes.CDLL'>类型。类型是没错的,但是_FuncPtr函数接收到QuickSort字符串时,却显示找不到这个函数;如果我们直接使用cpp,或者dll等文件,有显示: 不是有效的win32应用程序。
因为我们的执行环境是64位的,而visual studio是基于32位的,理论上有两种办法解决:
- 将python程序改成32位版本,当然这种方法对我们来说一般难以接受;
- 将外部链接编译为64位的,我在studio里面设置了x64,结果设置了一个寂寞。
为了不浪费太多时间,我将这部分搬到Ubuntu系统上进行测试。
1.4 Linux系统下加载编译后的文件
这里我们记录从文件生成到最终调用的全过程。
1.4.1 书写文档
$ sudo vim quik.c
# 将1.1的C++文件内容书写进文档并保持
1.4.2 编译、打包源文件
编译链接为可执行文件
$ sudo g++ -Wall quik.c -o quick
$ ./quick
-6 2 5 8 9
这里对main函数的默认数组进行了排序!
编译为目标文件
$ sudo g++ -Wall -c quik.c -o quick.o
$ ls
quick quick.o quik.c
生成静态链接库
$ sudo ar cr libquick.o quick.o
$ ls
libquick.o quick quick.o quik.c
生成动态链接库
$ sudo g++ -Wall -shared -fPIC quik.c -o libquick.so
$ ls
libquick.o libquick.so quick quick.o quik.c
1.4.3 python加载外部链接库
我们尝试从不同的文件进行加载,分别是c++源文件、可执行文件、.o目标文件、外部静态链接库、外部动态链接库。
首先说明结果:c++源文件、可执行文件都不能被加载。
加载c++源文件报错:OSError: quik.c: invalid ELF header
加载可执行文件quick报错:OSError: no file with expected extension
加载目标文件报错:OSError: quick.o: only ET_DYN and ET_EXEC can be loaded
加载外部静态链接库报错:OSError: libquick.o: invalid ELF header
加载外部动态链接库报错:undefined symbol:“QuickSort”
现在我们只能使用main函数,其他函数调用会报未定义符号的错误,下面我们先基于so动态链接库走通这个流程。
1.4.3.1 动态链接库使用成功案例
首先我们模拟正常的项目,进行独立编译。我们将quik文件拆分为quik.c和main.c。
问题的解决方案可以参考linux动态库so调用外部so,运行时出现undefined symbol
我们生成如下的quik.c和main.c文档:
#include <iostream>
using namespace std;
//extern "C" C++中编译c格式的函数,如果利用c语言编译不需要
extern "C" void QuickSort(int A[], int low, int high);
int Paritition1(int A[], int low, int high) {
int pivot = A[low];
while (low < high) {
while (low < high && A[high] >= pivot) {
--high;
}
A[low] = A[high];
while (low < high && A[low] <= pivot) {
++low;
}
A[high] = A[low];
}
A[low] = pivot;
return low;
}
void QuickSort(int A[], int low, int high) //快排母函数
{
if (low < high) {
int pivot = Paritition1(A, low, high);
QuickSort(A, low, pivot - 1);
QuickSort(A, pivot + 1, high);
}
}
#include <iostream>
using namespace std;
// 声明可以写 在 头文件中
extern "C" void QuickSort(int A[], int low, int high);
int main(){
int arr[5] = { 9, 2, 8, -6, 5 };
QuickSort(arr, 0, 4);
for (int i = 0; i < 4; i++){
cout << arr[i] << " ";
}
cout << arr[4] << endl;
}
上面我们使用extern进行了QuickSort函数的声明,这样就可以不使用quik.h头文件,要注意的是声明中使用的是“C”进行编译防止函数名被优化!基于此项改动就可以得到如下效果
python调用so动态链接库
$ sudo g++ -Wall -c main.c
$ sudo g++ -Wall -c quik.c -o quick.o
$ sudo g++ -Wall -shared -fPIC main.c quik.c -o libquick.so
$ python
>>> import numpy.ctypeslib as ctl
>>> ctl_lib = ctl.load_library("libquick.so", "./")
>>> import numpy as np
>>> arr_1d = ctl.ndpointer(
... dtype=np.int32,
... ndim=1,
... flags="CONTIGUOUS"
... )
>>> ctl_lib.QuickSort.restypes = None
>>> from ctypes import c_int, c_float
>>> ctl_lib.QuickSort.argtypes = [arr_1d, c_int, c_int]
>>> arr1 = np.array([5, -6, 8, 4, 7, 6, 3], dtype=np.int32)
>>> ctl_lib.QuickSort(arr1, 0, len(arr1))
>>> print(arr1)
[-6 3 4 5 6 7 8]
>>> type(arr1)
<class 'numpy.ndarray'>
注: 关于最好还是写在声明头文件中,main.c文件引入头文件;但是函数定义文件中的声明是一定要有的!
动态库可以,静态库却不可以?
直接加载quik.c源文件生成的静态链接库确实是不行!即使我们已经声明还是会有invalid ELF header错误,也不难理解,声明是解决不了这个问题的。鉴于我们常使用动态链接库,静态库该如何调用留作悬念吧。不过根据这个报错,很可能我们调用不起来。
1.4.3.2 python调用外部链接库总结
调用外部C/C++接口,我们最好使用动态链接库;
动态链接库生成的时候一定要注意进行声明
extern "C" void QuickSort(int A[], int low, int high);不然加载后会找不到函数名,这个名字会被优化成其他
更多细节可以参考官方文档https://scipy-cookbook.readthedocs.io/items/Ctypes.html
完!
ctypes与numpy.ctypeslib的使用的更多相关文章
- 小白眼中的AI之~Numpy基础
周末码一文,明天见矩阵- 其实Numpy之类的单讲特别没意思,但不稍微说下后面说实际应用又不行,所以大家就练练手吧 代码裤子: https://github.com/lotapp/BaseCode ...
- python调用C++实例:用C++对numpy执行BFS(广度优先搜索)
下文的代码可能展示不全,详情请下载文件:用cpp遍历ndarray.rar 问题背景: 现在我有一张二值图test.npy,需要对其闭区域进行孔洞填充,如下图所示: 文件下载链接:用cpp遍历ndar ...
- Python调用C/Fortran混合的动态链接库-下篇
接着前面的内容,我们在这里继续介绍Python传递二维数组到fortran并进行简单计算后返回的例子. 问题描述: module py2f90 use,intrinsic::iso_c_binding ...
- [Python] 06 - Modules --> Packages
故事背景 一.阶级关系 1. Programs are composed of modules.2. Modules contain statements.3. Statements contain ...
- python调用.so
python调用动态链接库的基本过程 动态链接库在Windows中为.dll文件,在linux中为.so文件.以linux平台为例说明python调用.so文件的使用方法. 本例中默认读者已经掌握动态 ...
- Python调用C/Fortran混合的动态链接库--中篇
接下来,介绍一个简单的例子,从fortran中传递并返回一维自定义结构体数组到python注意点:1.fortran新标准支持可分配数组作为变量传入并在subroutine或function分配后返回 ...
- Python调用C/Fortran混合的动态链接库--上篇
内容描述: 在32位或64位的windows或GNU/Linux系统下利用Python的ctypes和numpy模块调用C/Fortran混合编程的有限元数值计算程序 操作系统及编译环境: 32bit ...
- python调用c++类方法(2)
testpy.cpp: #include<iostream> #include<vector> struct point{ float pointx; float pointy ...
- 【转】Python调用C语言动态链接库
转自:https://www.cnblogs.com/fariver/p/6573112.html 动态链接库在Windows中为.dll文件,在linux中为.so文件.以linux平台为例说明py ...
随机推荐
- 华为C/C++编码规范+《数学之美》感想
1.排版 1.1 程序块要采用缩进风格编写, 缩进的空格数为4个.(说明: 对于由开发工具自动生成的代码可以有不一致)1.2 相对独立的程序块之间.变量说明之后必须加空行.1.3 循环.判断等语句中若 ...
- 手把手教你学Dapr - 6. 发布订阅
上一篇:手把手教你学Dapr - 5. 状态管理 介绍 发布/订阅模式允许微服务使用消息相互通信.生产者或发布者在不知道哪个应用程序将接收它们的情况下向主题发送消息.这涉及将它们写入输入通道.同样,消 ...
- Java 中控制执行流程
if-else 非常常用的流程控制非 if-else 莫属了,其中 else 是可选的,if 有两种使用方式 其一: if (Boolean-expression) { statement; } 其二 ...
- [luogu7092]计数题
由于$\mu(i)$,因此每一个素数最多存在1次,当$k=0$答案必然为0 根据莫比乌斯和欧拉函数的积性,答案与对素数的划分无关,仅与每一个素数是否出现有关,换言之枚举素数出现的集合$P'$,答案即为 ...
- class动态样式绑定
字符串,数组,对象
- idea中解决整合SSM加载不到dataSource;
idea在搭建maven的ssm项目中注入dataSource报错解决方案: 在整合ssm时候,发现 dataSource加载不到,并报错:解决办法为:file–>project structu ...
- Go语言核心36讲(Go语言实战与应用十四)--学习笔记
36 | unicode与字符编码 在开始今天的内容之前,我先来做一个简单的总结. Go 语言经典知识总结 在数据类型方面有: 基于底层数组的切片: 用来传递数据的通道: 作为一等类型的函数: 可实现 ...
- 咸阳市大数据管理局使用Rainbond作为智慧城市底座的实践
使用 Rainbond 作为智慧城市底座之后,给我们带来了成倍的运维效率提升. -- 咸阳市大数据管理局 熊礼智 咸阳市大数据管理局负责全市信息共享工作的组织领导,协调解决与政府信息共享有关的重大问题 ...
- Codeforces 375C - Circling Round Treasures(状压 dp+最短路转移)
题面传送门 注意到这题中宝藏 \(+\) 炸弹个数最多只有 \(8\) 个,故考虑状压,设 \(dp[x][y][S]\) 表示当前坐标为 \((x,y)\),有且仅有 \(S\) 当中的物品被包围在 ...
- Codeforces 796E - Exam Cheating(dp)
Codeforces 题目传送门 & 洛谷题目传送门 当被数据结构搞自闭的 tzc 信心满满地点开一道 *2400 的 dp 题时-- 却发现自己不会做?! 这足以证明蒟蒻 dp 之菜/dk/ ...