如果需要用 python 呼叫 c/c++ 編寫的第三方庫,只需要乙個指令碼語言來粘合它們。這個時候,用 python ctypes 可以很方便地實現呼叫。
stackoverflow 上的 calling c/c++ from python 這個主題介紹了 ctypes 最簡單的入門方法,概括如下:
如果是 c 函式庫,則直接 load 這個庫,然後呼叫即可;
如果是 c++ 函式庫,則需要用 extern 關鍵字封裝乙個供 c 使用的函式,即把類隱藏到一些 c 風格的函式裡,然後用 extern 標明這些函式,以方便外部呼叫。
這兩種方法裡,弄懂了 ctypes 呼叫 c++ 庫的方法,就會用 ctypes 呼叫 c 函式庫,對 c++ 庫的基本方法如下。
例如,有乙個 c++ 類 foo:
#includeclassfoo再封裝出下面 c 風格的介面函式:};
extern"c"voidfoo_bar(foo* foo)}
g++ -c -fpic foo.cpp -o foo.o,然後再用 python 寫的**來呼叫這個類,你可以把上面兩個 c 介面函式寫成 python 類,或是直接呼叫:g++ -shared -wl,-soname,libfoo.so -o libfoo.so foo.o
from ctypes import cdll
lib = cdll.loadlibrary('./libfoo.so')
class foo(object):
def __init__(self):
self.obj = lib.foo_new()
def bar(self):
lib.foo_bar(self.obj)
,然後就可以在 python 指令碼裡呼叫這個 python 類了:
f = foo()
f.bar() #and you will see "hello" on the screen
在 windows 下用 python ctypes 的方法和上面一樣,只是有下面兩點需要注意一下:
在編寫 python **時,剛開始鏈結所需的動態鏈結庫時,最好使用絕對路徑來 load,以減少出錯概率,加快除錯速度 在我按上面的方法編寫好了上述**時,一執行指令碼,則提示如下錯誤資訊:
$ python linkcpp.pytraceback (most recent call last):
file "linkcpp.py", line 2, in lib = cdll.loadlibrary('./linkexample')
file "c:\python27\lib\ctypes\__init__.py", line 431, in loadlibrary
return self._dlltype(name)
file "c:\python27\lib\ctypes\__init__.py", line 353, in __init__
self._handle = _dlopen(self._name, mode)
windowserror: [error 126]
from ctypes import cdll
lib = cdll.loadlibrary('./linkexample')
如果把 ./linkexample 這句換成 windows 下的絕對路徑 e:/pythoncode/linkcpp/linkexample,則沒有錯誤提示了。當然,你直接把 ./linkexample 換成 linkexample 也可以找到該鏈結庫。
所以,剛開始的時候,使用絕對路徑,以確保你不會糾結於能不能找到鏈結庫之類的問題。
在執行上述指令碼的時候,出現 windowserror: [error 126] 的錯誤,無非就是兩個原因:
另外,注意一下,windows 下因為庫分為 lib 和 dll 兩個檔案,所以可以只輸入庫的名稱即可,比如說你要鏈結 linkexample.dll 庫,則可以在 ctypes 裡只需要宣告鏈結名為 linkexample 庫即可。
如果是 c++ 寫的庫,需要用上 extern 關鍵字,這個和一般的供 c 呼叫的 c++ 庫標頭檔案是一樣的 在 extern 宣告的函式裡,可以使用 c++ 裡 c 沒有的關鍵字,比如我的函式就是這樣宣告的:
externintlinkexample(constintindex,constchar* name);上面**可以從 python 呼叫執行。
extern:extern可置於變數或者函式前,以表示變數或者函式的定義在別的檔案中,提示編譯器遇到此變數或函式時,在其它模組中尋找其定義。另外,extern也可用來進行鏈結指定。
親自實現
c++
g++編譯 g++ -o libpycallclass.so -shared -fpic ex.cpp
#include usingnamespace
std;
class
testlib
; void
testlib::display()
void testlib::display(int
a)
extern"c
" void
display_int()
}
python 呼叫
importctypes
so =ctypes.cdll.loadlibrary
lib = so("
./libpycallclass.so
")
'display()
'lib.display()
'display(100)
'lib.display_int(100)
1 2 作為一種技術的演算法
要研究演算法,哪些指標可以用來衡量演算法的好壞呢?1.這個演算法要能正確解決問題。這個是前提,研究演算法的最終目的也是為了解決問題。如果乙個演算法,不能解決問題,那要它何用。2.這個演算法占用的資源應該盡可能小。計算機可以做得很快,但不能無限快。儲存器很便宜,但不會免費。計算時間是一種有限的資源,儲...
一種協程的 C C 實現
在前幾天接觸到了協程的概念,覺得很有趣。因為我可以使用乙個執行緒來實現乙個類似多執行緒的程式,如果使用協程來替代執行緒,就可以省去很多原子操作和記憶體柵欄的麻煩,大大減少與執行緒同步相關的系統呼叫。因為我只有乙個執行緒,而且協程之間的切換是可以由函式自己決定的。我有見過幾種協程的實現,因為沒有 c ...
C C 中switch用法的一種替換方式
在c c 中,switch語句是經常被用到的,當switch內的case語句較多時程式有時顯得比較繁亂,此種情況下可以用另外一種實現方式替代switch。詳細用法見例子 include stdafx.h float addfunc float a,float b float subfunc floa...