爲了擴展Python,咱們能夠用C/C++編寫模塊,可是這要求對Python的底層有足夠的瞭解,包括Python對象模型、經常使用模塊、引用計數等,門檻較高,且不方便利用現有的C庫。而 ctypes 則另闢蹊徑,經過封裝dlopen/dlsym
之類的函數,並提供對C中數據結構的包裝/解包,讓Python可以加載動態庫、導出其中的函數直接加以利用。html
最簡單的,咱們能夠從 libc 開始:python
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個字符)linux
這裏有一個最簡單的例子——實現一個 int sum(int a, int b)
:windows
//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裏的內容,因此這裏須要變通一下。可能的解決方案有兩個:code
create_string_buffer
這個函數,正適合。那就讓咱們用方案2來實現它:orm
//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裏頭:server
>>> 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數據結構,具體的這裏不細說了,能夠參考詳細的官方文檔。
好了,就到這裏。