mirror of
https://github.com/apachecn/ailearning.git
synced 2026-02-10 22:05:11 +08:00
194 lines
2.6 KiB
Markdown
194 lines
2.6 KiB
Markdown
# ctypes
|
||
|
||
## 基本用法
|
||
|
||
`ctypes` 是一个方便 `Python` 调用本地已经编译好的外部库的模块。
|
||
|
||
In [1]:
|
||
|
||
```py
|
||
from ctypes import util, CDLL
|
||
|
||
```
|
||
|
||
## 标准 C 库
|
||
|
||
使用 `util` 来找到标准 `C` 库:
|
||
|
||
In [2]:
|
||
|
||
```py
|
||
libc_name = util.find_library('c')
|
||
|
||
# on WINDOWS
|
||
print libc_name
|
||
|
||
```
|
||
|
||
```py
|
||
msvcr90.dll
|
||
|
||
```
|
||
|
||
使用 `CDLL` 来加载 `C` 库:
|
||
|
||
In [3]:
|
||
|
||
```py
|
||
libc = CDLL(libc_name)
|
||
|
||
```
|
||
|
||
libc 包含 `C` 标准库中的函数:
|
||
|
||
In [4]:
|
||
|
||
```py
|
||
libc.printf
|
||
|
||
```
|
||
|
||
Out[4]:
|
||
|
||
```py
|
||
<_FuncPtr object at 0x0000000003CEE048>
|
||
```
|
||
|
||
调用这个函数:
|
||
|
||
In [5]:
|
||
|
||
```py
|
||
libc.printf("%s, %d\n", "hello", 5)
|
||
|
||
```
|
||
|
||
Out[5]:
|
||
|
||
```py
|
||
9
|
||
```
|
||
|
||
这里显示的 `9` 是 `printf` 的返回值表示显示的字符串的长度(包括结尾的 `'\0'`),但是并没有显示结果,原因是 `printf` 函数默认是写在标准输出流上的,与 `IPython` 使用的输出流不一样,所以没有显示结果。
|
||
|
||
## C 数学库
|
||
|
||
找到数学库:
|
||
|
||
In [6]:
|
||
|
||
```py
|
||
libm_name = util.find_library('m')
|
||
|
||
print libm_name
|
||
|
||
```
|
||
|
||
```py
|
||
msvcr90.dll
|
||
|
||
```
|
||
|
||
调用 `atan2` 函数:
|
||
|
||
In [7]:
|
||
|
||
```py
|
||
libm = CDLL(libm_name)
|
||
|
||
libm.atan2(1.0, 2.0)
|
||
|
||
```
|
||
|
||
```py
|
||
---------------------------------------------------------------------------
|
||
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` 函数的参数和返回值是什么样的:
|
||
|
||
In [8]:
|
||
|
||
```py
|
||
from ctypes import c_double
|
||
|
||
libm.atan2.argtypes = [c_double, c_double]
|
||
libm.atan2.restype = c_double
|
||
|
||
```
|
||
|
||
In [9]:
|
||
|
||
```py
|
||
libm.atan2(1.0, 2.0)
|
||
|
||
```
|
||
|
||
Out[9]:
|
||
|
||
```py
|
||
0.4636476090008061
|
||
```
|
||
|
||
与 `Python` 数学库中的结果一致:
|
||
|
||
In [10]:
|
||
|
||
```py
|
||
from math import atan2
|
||
|
||
```
|
||
|
||
In [11]:
|
||
|
||
```py
|
||
atan2(1.0, 2.0)
|
||
|
||
```
|
||
|
||
Out[11]:
|
||
|
||
```py
|
||
0.4636476090008061
|
||
```
|
||
|
||
## Numpy 和 ctypes
|
||
|
||
假设我们有这样的一个函数:
|
||
|
||
```py
|
||
float _sum(float *vec, int len) {
|
||
float sum = 0.0;
|
||
int i;
|
||
for (i = 0; i < len; i++) {
|
||
sum += vec[i];
|
||
}
|
||
return sum
|
||
}
|
||
|
||
```
|
||
|
||
并且已经编译成动态链接库,那么我们可以这样调用:
|
||
|
||
```py
|
||
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(<path>)
|
||
|
||
ptr = ndpointer(float32, ndim=1, flags='C')
|
||
lib._sum.argtypes = [ptr, c_int]
|
||
lib._sum.restype = c_float
|
||
|
||
result = lib._sum(x, len(x))
|
||
|
||
``` |