3 回答

TA貢獻1785條經(jīng)驗 獲得超4個贊
ctypes 是快速完成它的最佳選擇,并且在仍在編寫Python的情況下很高興與您合作!
我最近包裝了一個FTDI驅動程序,用于使用ctypes與USB芯片通信,這很棒。我完成了所有工作,并在不到一天的時間內完成工作。(我只實現(xiàn)了我們需要的功能,大約有15個功能)。
出于同一目的,我們以前使用的是第三方模塊PyUSB。PyUSB是實際的C / Python擴展模塊。但是PyUSB在阻止讀寫操作時沒有釋放GIL,這給我們帶來了問題。因此,我使用ctypes編寫了自己的模塊,該模塊在調用本機函數(shù)時會釋放GIL。
需要注意的一件事是,ctypes不會知道#define所使用的庫中的常量和內容,而僅是函數(shù),因此您必須在自己的代碼中重新定義這些常量。
這是一個代碼最終的外觀示例(大量內容被刪除,只是試圖向您展示其要旨):
from ctypes import *
d2xx = WinDLL('ftd2xx')
OK = 0
INVALID_HANDLE = 1
DEVICE_NOT_FOUND = 2
DEVICE_NOT_OPENED = 3
...
def openEx(serial):
serial = create_string_buffer(serial)
handle = c_int()
if d2xx.FT_OpenEx(serial, OPEN_BY_SERIAL_NUMBER, byref(handle)) == OK:
return Handle(handle.value)
raise D2XXException
class Handle(object):
def __init__(self, handle):
self.handle = handle
...
def read(self, bytes):
buffer = create_string_buffer(bytes)
count = c_int()
if d2xx.FT_Read(self.handle, buffer, bytes, byref(count)) == OK:
return buffer.raw[:count.value]
raise D2XXException
def write(self, data):
buffer = create_string_buffer(data)
count = c_int()
bytes = len(data)
if d2xx.FT_Write(self.handle, buffer, bytes, byref(count)) == OK:
return count.value
raise D2XXException
有人對各種選項做了一些基準測試。
如果不得不包裝帶有許多類/模板/等的C ++庫,我可能會更加猶豫。但是ctypes可以很好地與結構配合使用,甚至可以回調到Python中。

TA貢獻1860條經(jīng)驗 獲得超8個贊
警告:Cython核心開發(fā)人員的意見。
我?guī)缀蹩偸墙ㄗhCython勝過ctypes。原因是它具有更平滑的升級路徑。如果使用ctypes,一開始很多事情都會很簡單,用純Python編寫FFI代碼當然很酷,而無需編譯,構建依賴關系以及所有這些。但是,在某個時候,您幾乎肯定會發(fā)現(xiàn),您必須循環(huán)或以更長的一系列相互依賴的調用方式大量調用C庫,并且您希望加快速度。在這一點上,您會注意到無法使用ctypes做到這一點?;蛘?,當您需要回調函數(shù)并且發(fā)現(xiàn)您的Python回調代碼成為瓶頸時,您也想加快它的速度和/或也將它移入C。同樣,您不能使用ctypes做到這一點。
使用OTOH的Cython,您可以完全自由地使包裝和調用代碼變薄或變厚。您可以從對常規(guī)Python代碼的C代碼中進行簡單的調用開始,然后Cython會將它們轉換為本地C調用,而沒有任何額外的調用開銷,并且Python參數(shù)的轉換開銷非常低。當您發(fā)現(xiàn)需要對C庫進行太多昂貴的調用時,甚至在某些時候需要更高的性能時,可以開始使用靜態(tài)類型注釋周圍的Python代碼,并讓Cython為您直接對其進行優(yōu)化?;蛘撸梢蚤_始在Cython中重寫部分C代碼,以避免調用并在算法上專門化和加強循環(huán)。如果您需要快速回調,只需編寫具有適當簽名的函數(shù),然后將其直接傳遞到C回調注冊表即可。同樣,沒有開銷,并且它為您提供普通的C調用性能。而且在不太可能發(fā)生的情況下,您實際上無法在Cython中獲得足夠快的代碼,您仍然可以考慮用C(或C ++或Fortran)重寫其真正關鍵的部分,并自然地從本地從Cython代碼中調用它。但是,這實際上成了最后的選擇,而不是唯一的選擇。
因此,ctypes非常適合做簡單的事情并快速使某些事情運行。但是,一旦事情開始發(fā)展,您很可能會發(fā)現(xiàn)您最好從一開始就使用Cython。
添加回答
舉報