Ctypes和NumPy

19 Ctypes和NumPy

19.1 用ctypes加速计算

Ctypes是Python处理动态链接库的标准扩展模块,在Windows下使用它可以直接调用C语言编写的DLL动态链接库。由于对传递的参数没有类型和越界检查,因此如果编写的代码有问题的话,很可能会造成程序崩溃。当将数组数据使用指针传递时,出错误的风险将更加大。

为了让程序更加安全,通常会用Python代码对Ctypes调用进行包装,在调用Ctypes之前,在Python级别对数据类型和越界进行检查。这样做会使得调用接口部分比其它的一些手工编写的扩展模块速度要慢,但是如果C语言的代码段处理相当多的数据的话,接口调用部分的速度损失是可以忽略不计的。

19.2 用ctypes调用DLL

为了使用CTypes,你必须依次完成以下步骤:

  • 编写动态连接库程序
  • 载入动态连接库
  • 将Python的对象转换为ctypes所能识别的参数
  • 使用ctypes的参数调用动态连接库中的函数

下面我们来看看如何用ctypes调用动态链接库。

19.3 numpy对ctypes的支持

为了方便动态连接库的载入,numpy提供了一个便捷函数ctypeslib.load_library。它有两个参数,第一个参数是库的文件名,第二个参数是库所在的路径。函数返回的是一个ctypes的对象。通过此对象的属性可以直接到动态连接库所提供的函数。

例如如果我们有一个库名为test_sum.dll,其中提供了一个函数mysum :

double mysum(double a[], long n)
{
    double sum = 0;
    int i;
    for(i=0;i<n;i++) sum += a[i];
    return sum;
}

的话,我们可以使用如下语句载入此库:

>>> from ctypes import *
>>> sum_test = np.ctypeslib.load_library("sum_test", ".")
>>> print sum_test.mysum
<_FuncPtr object at 0x037D7210>

要正确调用sum函数,还必须对其参数类型进行说明,下面的语句描述了sum函数的两个参数的类型和返回值的类型进行描述:

>>> sum_test.mysum.argtypes = [POINTER(c_double), c_long]
>>> sum_test.mysum.restype = c_double

接下来就可以正常调用sum函数了:

>>> x = np.arange(1, 101, 1.0)
>>> sum_test.mysum(x.ctypes.data_as(POINTER(c_double)), len(x))
5050.0

每次调用sum都需要进行类型转换时比较麻烦的事情,因此可以编写一个Python的mysum函数,将C语言的mysum函数包装起来:

def mysum(x):
    return sum_test.mysum(x.ctypes.data_as(POINTER(c_double)), len(x))

在上面的例子中,test_sum.mysum的参数值使用标准的ctypes类型声明:用POINTER(c_double)声明mysum函数的第一个参数是一个指向double的指针;然后调用数组x的x.ctypes.data_as函数将x转换为一个指向double的指针类型。

由于数组的元素在内存中的存储可以是不连续的,而且可以是多维数组,因此我们不能指望前面的mysum函数能够处理所有的情况:

>>> x = np.arange(1,11,1.0)
>>>  mysum(x[::2])
15.0
>>> sum(x[::2])
25.0

由于x[::2]和x共同一块内存空间,而x[::2]中的元素是不连续的,每个元素之间的间隔为16byptes(2个double的大小)。因此将它传递给mysum的话,实际上计算的是x数组中前5项的和:1+2+3+4+5=15,而实际上我们希望的结果是:1+3+5+7+9=25。

为了对传递的数组参数进行更加详细的描述,numpy库提供了ndpointer函数。ndpointer函数对restype和argtypes中的数组参数进行描述,他有如下4个参数:

  • dtype : 数组的元素类型
  • ndim : 数组的维数
  • shape : 数组的形状,各个轴的长度
  • flags : 数组的标志

例如:

test_sum.mysum.argtypes = [
    np.ctypeslib.ndpointer(dtype=np.float64, ndim=1, flags="C_CONTIGUOUS"),
    c_long
]

描述了sumfunc函数的参数为一个元素类型为double的、一维的、连续的元素按C语言规定排列的数组。

这时传递给mysum函数的第一个参数可以直接是数组,因此无需再编写一个Python函数对其进行包装:

>>> sum_test.mysum(x,len(x))
55.0
>>> sum_test.mysum(x[::2],len(x)/2)
ArgumentError: argument 1: <type 'exceptions.TypeError'>:
array must have flags ['C_CONTIGUOUS']

我们注意到如果参数数组不是连续空间的话,mysum函数的调用会抛出异常错误,提醒我们其参数需要C语言排列的连续数组。

如果我们希望它能够处理多维、不连续的数组的话,就需要把数组的shape和strides属性都传递给过去。假设我们想写一个通用的mysum2函数,它可以对二维数组的所有元素进行求和。下面是C语言的程序:

double mysum2(double a[], int strides[], int shapes[])
{
    double sum = 0;
    int i, j, M, N, S0, S1;
    M = shape[0]; N=shape[1];
    S0 = strides[0] / sizeof(double);
    S1 = strides[1] / sizeof(double);

    for(i=0;i<M;i++){
        for(j=0;j<N;j++){
            sum += a[i*S0 + j*S1];
        }
    }
    return sum;
}

mysum2函数有3个参数,第一个参数a[]指向保存数组数据的内存块;第二个参数astrides指向保存数组各个轴元素之间的间隔(以byte为单位);第三个参数dims指向保存数组各个轴长度的数组。

由于strides保存的是以byte为单位的间隔长度,因此需要除以sizeof(double)计算出以double为单位的间隔长度S0和S1。这样二维数组a中的第i行、第j列的元素可以通过a[i*S0 + j*S1]来存取。下面用ctypes对mysum2函数进行包装:

sum_test.mysum2.restype = c_double
sum_test.mysum2.argtypes = [
    np.ctypeslib.ndpointer(dtype=np.float64, ndim=2),
    POINTER(c_int),
    POINTER(c_int)
]

def mysum2(x):
    return sum_test.mysum2(x, x.ctypes.strides, x.ctypes.shape)

在mysum2函数中,为了将数组x的strides和shape属性传递给C语言的函数,可以使用x.ctypes中提供的strides和shape属性。注意不能直接传递x.strides和x.shape,因为这些是python的tuple对象,而x.ctypes.shape得到的是ctypes包装的整数数组:

>>> x = np.zeros((3,4), np.float)
>>> x.ctypes.shape
<numpy.core._internal.c_long_Array_2 object at 0x020B4DF0>
>>> s = x.ctypes.shape
>>> s[0]
3
>>> s[1]
4

可以看出x.ctypes.shape是一个有两个元素的C语言长整型数组。虽然我们也可以在Python中通过下标读取其各个元素的值,但是通常它们是作为参数传递给C语言函数用的。


文章转自:http://hyry.dip.jp/pydoc/ctypes_numpy.html#ctypes


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
说明:本文档所有内容来源于网络 https://www.numpy.org.cn/user/ 目录 1. NUMPY 介绍 1 1.1 什么是 NUMPY? 1 1.2 为什么 NUMPY 这么快? 3 1.3 还有谁在使用 NUMPY? 3 2. 快速入门教程 4 2.1 先决条件 4 2.2 基础知识 4 2.2.1一个例子 5 2.2.2 数组创建 6 2.2.3 打印数组 8 2.2.4 基本操作 10 2.2.5 通函数 13 2.2.6 索引、切片和迭代 14 2.3 形状操纵 18 2.3.1改变数组的形状 18 2.3.2 将不同数组堆叠在一起 20 2.3.3 将一个数组拆分成几个较小的数组 22 2.4 拷贝和视图 23 2.4.1 完全不复制 23 2.4.2 视图或浅拷贝 24 2.4.3 深拷贝 25 2.4.4 功能和方法概述 26 2.5 LESS 基础 26 广播(Broadcasting)规则 27 2.6 花式索引和索引技巧 27 2.6.1使用索引数组进行索引 27 2.6.2使用布尔数组进行索引 31 2.6.3 ix_()函数 34 2.6.4使用字符串建立索引 37 2.7线性代数 37 简单数组操作 37 2.8技巧和提示 38 2.8.1“自动”整形 39 2.8.2矢量堆叠 39 2.8.3直方图 40 2.9进一步阅读 41 3. NUMPY 基础知识 42 3.1 数据类型 42 3.1.1 数组类型之间的转换 42 3.1.2 数组标量 45 3.1.3 溢出错误 46 3.1.4 扩展精度 47 3.2 创建数组 47 3.2.1 简介 48 3.2.2 将Python array_like对象转换为Numpy数组 48 3.2.3 Numpy原生数组的创建 48 3.2.4 从磁盘读取数组 50 3.3 NUMPY与输入输出 51 3.3.1 定义输入 51 3.3.2 将行拆分为列 52 3.3.3 跳过直线并选择列 54 3.3.4 选择数据的类型 55 3.3.5 设置名称 56 3.3.6 调整转换 59 3.3.7 快捷方式函数 62 3.4 索引 62 3.4.1 赋值与引用 63 3.4.2 单个元素索引 63 3.4.3 其他索引选项 64 3.4.4 索引数组 65 3.4.5 索引多维数组 66 3.4.6 布尔或“掩码”索引数组 67 3.4.7 将索引数组与切片组合 69 3.4.8 结构索引工具 70 3.4.9 为索引数组赋值 71 3.4.10 在程序中处理可变数量的索引 72 3.5 广播 73 3.6 字节交换 78 3.6.1字节排序和ndarrays简介 78 3.6.2 更改字节顺序 80 3.7 结构化数组 82 3.7.1 介绍 82 3.7.2 结构化数据类型 83 3.7.3 索引和分配给结构化数组 88 3.7.4 记录数组 96 3.7.5 Recarray Helper 函数 98 3.8编写自定义数组容器 116 3.9子类化NDARRAY 124 3.9.1 介绍 124 3.9.2 视图投影 125 3.9.3 从模板创建 126 3.9.4 视图投影与从模板创建的关系 126 3.9.5 子类化的含义 126 3.9.6 简单示例 —— 向ndarray添加额外属性 132 3.9.7 稍微更现实的例子 —— 添加到现有数组的属性 134 3.9.8 __array_ufunc__ 对于ufuncs 135 3.9.9 __array_wrap__用于ufuncs和其他函数 139 3.9.10 额外的坑 —— 自定义的 __del__ 方法和 ndarray.base 142 3.9.11 子类和下游兼容性 143 4. 其他杂项 144 4.1 IEEE 754 浮点特殊值 144 4.2 NUMPY 如何处理数字异常的 146 4.3 示例 146 4.4 连接到 C 的方式 147 4.4.1 不借助任何工具, 手动打包你的C语言代码。 147 4.4.2 Cython 148 4.4.3 ctypes 148 4.4.4 SWIG(自动包装发生器) 149 4.4.5 scipy.weave 149 4.4.6 Psyco 149 5. 与MATLAB比较 149 5.1 介绍 150 5.2 一些关键的差异 150 5.3 'ARRAY'或'MATRIX'?我应该使用哪个? 151 5.3.1 简答 151 5.3.2 长答案 151 5.4 MATLAB 和 NUMPY粗略的功能对应表 153 5.4.1 一般功能的对应表 153 5.4.2 线性代数功能对应表 154 5.5 备注 161 5.6 自定义您的环境 163 5.7 链接 164 6. 从源代码构建 164 6.1 先决条件 164 6.2 基本安装 164 6.3 测试 165 并行构建 165 6.4 FORTRAN ABI不匹配 165 6.4.1 选择fortran编译器 166 6.4.2 如何检查BLAS / LAPACK /地图集ABI 166 6.5 加速BLAS / LAPACK库 166 6.5.1 BLAS 166 6.5.2 LAPACK 167 6.5.3 禁用ATLAS和其他加速库 167 6.6 提供额外的编译器标志 168 6.7 使用ATLAS支持构建 168 7. 使用NUMPY的C-API 168 7.1 如何扩展NUMPY 168 7.1.1 编写扩展模板 169 7.1.2 必需的子程序 169 7.1.3 定义函数 171 7.1.4 处理数组对象 175 7.1.5 示例 180 7.2 使用PYTHON作为胶水 182 7.2.1 从Python调用其他编译库 183 7.2.2 手工生成的包装器 183 7.2.3 f2py 184 7.2.4 用Cython 191 7.2.5 ctypes 196 7.2.6 您可能会觉得有用的其他工具 206 7.3 编写自己的UFUNC 208 7.3.1 创建一个新的ufunc 208 7.3.2 示例非ufunc扩展名 209 7.3.3 一种dtype的NumPy ufunc示例 215 7.3.4 示例具有多个dtypes的NumPy ufunc 221 7.3.5 示例具有多个参数/返回值的NumPy ufunc 230 7.3.6 示例带有结构化数组dtype参数的NumPy ufunc 235 7.4 深入的知识 241 7.4.1 迭代数组中的元素 242 7.4.2 用户定义的数据类型 246 7.4.3 在C中对ndarray进行子类型化 249
CONTENTS 1 Arrayobjects 3 1.1 TheN-dimensionalarray(ndarray).................................. 3 1.2 Scalars.................................................. 73 1.3 Datatypeobjects(dtype)........................................110 1.4 Indexing.................................................121 1.5 Standardarraysubclasses........................................125 1.6 Maskedarrays..............................................250 1.7 TheArrayInterface ...........................................433 2 Universalfunctions(ufunc) 439 2.1 Broadcasting...............................................439 2.2 Outputtypedetermination........................................440 2.3 Useofinternalbuffers..........................................440 2.4 Errorhandling..............................................440 2.5 CastingRules...............................................443 2.6 ufunc..................................................445 2.7 Availableufuncs.............................................452 3 Routines 457 3.1 Arraycreationroutines..........................................457 3.2 Arraymanipulationroutines.......................................488 3.3 Indexingroutines.............................................522 3.4 Datatyperoutines............................................547 3.5 Inputandoutput.............................................559 3.6 DiscreteFourierTransform(numpy.fft)...............................579 3.7 Linearalgebra(numpy.linalg) ...................................599 3.8 Randomsampling(numpy.random) .................................627 3.9 Sortingandsearching ..........................................678 3.10Logicfunctions..............................................691 3.11Binaryoperations.............................................707 3.12Statistics.................................................715 3.13Mathematicalfunctions .........................................735 3.14Functionalprogramming.........................................794 3.15Polynomials...............................................799 3.16Financialfunctions............................................812 3.17Setroutines................................................820 3.18Windowfunctions............................................825 3.19Floatingpointerrorhandling.......................................836 3.20Maskedarrayoperations.........................................842 i 3.21Numpy-specifichelpfunctions......................................962 3.22Miscellaneousroutines..........................................965 3.23TestSupport(numpy.testing)....................................966 3.24Asserts..................................................967 3.25Mathematicalfunctionswithautomaticdomain(numpy.emath)...................977 3.26Matrixlibrary(numpy.matlib)....................................977 3.27OptionallyScipy-acceleratedroutines(numpy.dual).........................977 3.28Numarraycompatibility(numpy.numarray).............................978 3.29OldNumericcompatibility(numpy.oldnumeric)..........................978 3.30C-TypesForeignFunctionInterface(numpy.ctypeslib)......................978 3.31Stringoperations.............................................979 4 Packaging(numpy.distutils) 1013 4.1 Modulesinnumpy.distutils....................................1013 4.2 BuildingInstallableClibraries......................................1024 4.3 Conversionof.srcfiles ........................................1025 5 NumpyC-API 1027 5.1 PythonTypesandC-Structures .....................................1027 5.2 Systemconfiguration...........................................1041 5.3 DataTypeAPI..............................................1043 5.4 ArrayAPI ................................................1045 5.5 UFuncAPI................................................1078 5.6 GeneralizedUniversalFunctionAPI...................................1083 5.7 Numpycorelibraries...........................................1085 6 Numpyinternals 1089 6.1 NumpyCCodeExplanations ......................................1089 6.2 Internalorganizationofnumpyarrays..................................1096 6.3 MultidimensionalArrayIndexingOrderIssues.............................1097 7 NumpyandSWIG 1099 7.1 Numpy.i:aSWIGInterfaceFileforNumPy...............................1099 7.2 Testingthenumpy.iTypemaps......................................1112 8 Acknowledgements 1115 Bibliography 1117 PythonModuleIndex 1123 Index 1125

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值