运用ctypes来扩大Python

为了扩大Python,我们可以用C/C++编写模块,然则这请求对Python的底层有充足的相识,包含Python对象模子、经常运用模块、援用计数等,门坎较高,且不轻易应用现有的C库。而 ctypes 则另辟蹊径,经由过程封装dlopen/dlsym之类的函数,并供应对C中数据构造的包装/解包,让Python可以加载动态库、导出个中的函数直接加以应用。

疾速上手

最简朴的,我们可以从 libc 最先:

felix021@ubserver:~/code$ python
Python 2.7.3 (default, Jul  5 2013, 08:39:51) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import ctypes
>>> libc = ctypes.CDLL("libc.so.6")
>>> libc.printf("hello, %s! %d + %d = %d\n", "world", 1, 2, 3)
hello, world! 1 + 2 = 3
25

因为ctypes库可以直接处置惩罚 None, integers, longs, byte strings 和 unicode strings 范例的转换,因而在这里不须要任何分外的操纵就可以完成使命。(注重,末了一行的25是printf的返回值,标识输出了25个字符)

本身着手

这里有一个最简朴的例子——完成一个 int sum(int a, int b)

//file foo.c
#ifdef __WIN32
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT
#endif

DLLEXPORT int sum(int a, int b)
{
    return a + b;
}

编译之获得 foo.so:

$ gcc -fPIC -shared -o foo.so foo.c

然后在Python里头:

>>> foo = ctypes.CDLL("./foo.so")
>>> foo.sum(5, 3)
8

真是超等简朴。

饱食暖衣

下面来个轻微庞杂点的例子:反转一个字符串。只管ctypes可以直接处置惩罚string的转换,然则你不能直接修正string里的内容,所以这里须要变通一下。能够的解决计划有两个:

  1. 在foo.c内里malloc一点空间然后返回。如许可以不修正原string,然则却要斟酌开释该空间的题目,不太好处置惩罚。
  2. 让Python分派好空间,将原字符串拷贝进去,再让foo内里的函数来修正它。ctypes为这类计划供应了create_string_buffer这个函数,正合适。

那就让我们用计划2来完成它:

//file foo.c
DLLEXPORT int reverse(char *str)
{
    int i, j, t;
    for (i = 0, j = strlen(str) - 1; i < j; i++, j--)
        t = str[i], str[i] = str[j], str[j] = t;
    return 0;
}

然后在Python里头:

>>> s = ctypes.create_string_buffer("hello world!")
>>> foo.reverse(s)
0
>>> print s.value
!dlrow olleh

如许就OK啦。

补充申明

以上的操纵都是在Linux下完成的,在Windows下基本上一致,除了windows不能直接load libc.so.6,而是应当找 msvcrt :

>>> libc = ctypes.cdll.msvcrt

或许直接导入文件

>>> libc = ctypes.CDLL("msvcr90.dll")

小结

前面演示了ctypes库的简朴运用,已可以完成很多使命了;然则它可以完成更多的使命,包含操纵更庞杂的比方构造体、数组等C数据构造,细致的这里不细说了,可以参考细致的官方文档

好了,就到这里。

    原文作者:felix021
    原文地址: https://segmentfault.com/a/1190000000265262
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞