07.08 ctypes
ctypes
基本用法
ctypes 是一个方便 Python 调用本地已经编译好的外部库的模块。
1from ctypes import util, CDLL
标准 C 库
使用 util 来找到标准 C 库:
1libc_name = util.find_library('c')
2
3# on WINDOWS
4print libc_name
msvcr90.dll
使用 CDLL 来加载 C 库:
1libc = CDLL(libc_name)
libc 包含 C 标准库中的函数:
1libc.printf
<_FuncPtr object at 0x0000000003CEE048>
调用这个函数:
1libc.printf("%s, %d\n", "hello", 5)
9
这里显示的 9 是 printf 的返回值表示显示的字符串的长度(包括结尾的 '\0'),但是并没有显示结果,原因是 printf 函数默认是写在标准输出流上的,与 IPython 使用的输出流不一样,所以没有显示结果。
C 数学库
找到数学库:
1libm_name = util.find_library('m')
2
3print libm_name
msvcr90.dll
调用 atan2 函数:
1libm = CDLL(libm_name)
2
3libm.atan2(1.0, 2.0)
---------------------------------------------------------------------------
ArgumentError Traceback (most recent call last)
<ipython-input-7-e784e41ee9f3> in <module>()
1 libm = CDLL(libm_name)
2
----> 3 libm.atan2(1.0, 2.0)
ArgumentError: argument 1: <type 'exceptions.TypeError'>: Don't know how to convert parameter 1
调用这个函数出错,原因是我们需要进行一些额外工作,告诉 Python 函数的参数和返回值是什么样的:
1from ctypes import c_double
2
3libm.atan2.argtypes = [c_double, c_double]
4libm.atan2.restype = c_double
1libm.atan2(1.0, 2.0)
0.4636476090008061
与 Python 数学库中的结果一致:
1from math import atan2
1atan2(1.0, 2.0)
0.4636476090008061
Numpy 和 ctypes
假设我们有这样的一个函数:
1float _sum(float *vec, int len) {
2 float sum = 0.0;
3 int i;
4 for (i = 0; i < len; i++) {
5 sum += vec[i];
6 }
7 return sum
8}
并且已经编译成动态链接库,那么我们可以这样调用:
1from ctypes import c_float, CDLL, c_int
2from numpy import array, float32
3from numpy.ctypeslib import ndpointer
4
5x = array([1,2,3,4], dtype=float32)
6
7lib = CDLL(<path>)
8
9ptr = ndpointer(float32, ndim=1, flags='C')
10lib._sum.argtypes = [ptr, c_int]
11lib._sum.restype = c_float
12
13result = lib._sum(x, len(x))