ctypes
基本用法
ctypes
是一個友善
Python
調用本地已經編譯好的外部庫的子產品。
from ctypes import util, CDLL
标準 C 庫
使用
util
來找到标準
C
庫:
libc_name = util.find_library('c')
# on WINDOWS
print libc_name
msvcr90.dll
使用
CDLL
來加載
C
庫:
libc = CDLL(libc_name)
libc 包含
C
标準庫中的函數:
libc.printf
<_FuncPtr object at 0x0000000003CEE048>
調用這個函數:
libc.printf("%s, %d\n", "hello", 5)
9
這裡顯示的
9
是
printf
的傳回值表示顯示的字元串的長度(包括結尾的
'\0'
),但是并沒有顯示結果,原因是
printf
函數預設是寫在标準輸出流上的,與
IPython
使用的輸出流不一樣,是以沒有顯示結果。
C 數學庫
找到數學庫:
libm_name = util.find_library('m')
print libm_name
msvcr90.dll
調用
atan2
函數:
libm = CDLL(libm_name)
libm.atan2(1.0, 2.0)
---------------------------------------------------------------------------
ArgumentError Traceback (most recent call last)
in ()
1 libm = CDLL(libm_name)
2
----> 3 libm.atan2(1.0, 2.0)
ArgumentError: argument 1: : Don't know how to convert parameter 1
調用這個函數出錯,原因是我們需要進行一些額外工作,告訴
Python
函數的參數和傳回值是什麼樣的:
from ctypes import c_double
libm.atan2.argtypes = [c_double, c_double]
libm.atan2.restype = c_double
libm.atan2(1.0, 2.0)
0.4636476090008061
與
Python
數學庫中的結果一緻:
from math import atan2
atan2(1.0, 2.0)
0.4636476090008061
Numpy 和 ctypes
假設我們有這樣的一個函數:
float _sum(float *vec, int len) {
float sum = 0.0;
int i;
for (i = 0; i < len; i++) {
sum += vec[i];
}
return sum
}
并且已經編譯成動态連結庫,那麼我們可以這樣調用:
from ctypes import c_float, CDLL, c_int
from numpy import array, float32
from numpy.ctypeslib import ndpointer
x = array([1,2,3,4], dtype=float32)
lib = CDLL()
ptr = ndpointer(float32, ndim=1, flags='C')
lib._sum.argtypes = [ptr, c_int]
lib._sum.restype = c_float
result = lib._sum(x, len(x))