ctypes

基本用法

ctypes 是一个方便 Python 调用本地已经编译好的外部库的模块。

In [1]:

  1. from ctypes import util, CDLL

标准 C 库

使用 util 来找到标准 C 库:

In [2]:

  1. libc_name = util.find_library('c')
  2.  
  3. # on WINDOWS
  4. print libc_name
  1. msvcr90.dll

使用 CDLL 来加载 C 库:

In [3]:

  1. libc = CDLL(libc_name)

libc 包含 C 标准库中的函数:

In [4]:

  1. libc.printf

Out[4]:

  1. <_FuncPtr object at 0x0000000003CEE048>

调用这个函数:

In [5]:

  1. libc.printf("%s, %d\n", "hello", 5)

Out[5]:

  1. 9

这里显示的 9printf 的返回值表示显示的字符串的长度(包括结尾的 '\0'),但是并没有显示结果,原因是 printf 函数默认是写在标准输出流上的,与 IPython 使用的输出流不一样,所以没有显示结果。

C 数学库

找到数学库:

In [6]:

  1. libm_name = util.find_library('m')
  2.  
  3. print libm_name
  1. msvcr90.dll

调用 atan2 函数:

In [7]:

  1. libm = CDLL(libm_name)
  2.  
  3. libm.atan2(1.0, 2.0)
  1. ---------------------------------------------------------------------------
  2. ArgumentError Traceback (most recent call last)
  3. <ipython-input-7-e784e41ee9f3> in <module>()
  4. 1 libm = CDLL(libm_name)
  5. 2
  6. ----> 3 libm.atan2(1.0, 2.0)
  7.  
  8. ArgumentError: argument 1: <type 'exceptions.TypeError'>: Don't know how to convert parameter 1

调用这个函数出错,原因是我们需要进行一些额外工作,告诉 Python 函数的参数和返回值是什么样的:

In [8]:

  1. from ctypes import c_double
  2.  
  3. libm.atan2.argtypes = [c_double, c_double]
  4. libm.atan2.restype = c_double

In [9]:

  1. libm.atan2(1.0, 2.0)

Out[9]:

  1. 0.4636476090008061

Python 数学库中的结果一致:

In [10]:

  1. from math import atan2

In [11]:

  1. atan2(1.0, 2.0)

Out[11]:

  1. 0.4636476090008061

Numpy 和 ctypes

假设我们有这样的一个函数:

  1. float _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. }

并且已经编译成动态链接库,那么我们可以这样调用:

  1. from ctypes import c_float, CDLL, c_int
  2. from numpy import array, float32
  3. from numpy.ctypeslib import ndpointer
  4.  
  5. x = array([1,2,3,4], dtype=float32)
  6.  
  7. lib = CDLL(<path>)
  8.  
  9. ptr = ndpointer(float32, ndim=1, flags='C')
  10. lib._sum.argtypes = [ptr, c_int]
  11. lib._sum.restype = c_float
  12.  
  13. result = lib._sum(x, len(x))

原文: https://nbviewer.jupyter.org/github/lijin-THU/notes-python/blob/master/07-interfacing-with-other-languages/07.08-ctypes.ipynb