15.1 使用ctypes访问C代码?
问题?
你有一些C函数已经被编译到共享库或DLL中。你希望可以使用纯Python代码调用这些函数,
而不用编写额外的C代码或使用第三方扩展工具。
解决方案?
对于需要调用C代码的一些小的问题,通常使用Python标准库中的 ctypes
模块就足够了。
要使用 ctypes
,你首先要确保你要访问的C代码已经被编译到和Python解释器兼容
(同样的架构、字大小、编译器等)的某个共享库中了。
为了进行本节的演示,假设你有一个共享库名字叫 libsample.so
,里面的内容就是15章介绍部分那样。
另外还假设这个 libsample.so
文件被放置到位于 sample.py
文件相同的目录中了。
要访问这个函数库,你要先构建一个包装它的Python模块,如下这样:
# sample.py
import ctypes
import os
# Try to locate the .so file in the same directory as this file
_file = ‘libsample.so‘
_path = os.path.join(*(os.path.split(__file__)[:-1] + (_file,)))
_mod = ctypes.cdll.LoadLibrary(_path)
# int gcd(int, int)
gcd = _mod.gcd
gcd.argtypes = (ctypes.c_int, ctypes.c_int)
gcd.restype = ctypes.c_int
# int in_mandel(double, double, int)
in_mandel = _mod.in_mandel
in_mandel.argtypes = (ctypes.c_double, ctypes.c_double, ctypes.c_int)
in_mandel.restype = ctypes.c_int
# int divide(int, int, int *)
_divide = _mod.divide
_divide.argtypes = (ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_int))
_divide.restype = ctypes.c_int
def divide(x, y):
rem = ctypes.c_int()
quot = _divide(x, y, rem)
return quot,rem.value
# void avg(double *, int n)
# Define a special type for the ‘double *‘ argument
class DoubleArrayType:
def from_param(self, param):
typename = type(param).__name__
if hasattr(self, ‘from_‘ + typename):
return getattr(self, ‘from_‘ + typename)(param)
elif isinstance(param, ctypes.Array):
return param
else:
raise TypeError("Can‘t convert %s" % typename)
# Cast from array.array objects
def from_array(self, param):
if param.typecode != ‘d‘:
raise TypeError