2008-08-19 50 views
19

我一直在考慮一段時間來編寫一個峯值擬合庫。我很瞭解Python,並計劃在Python中實現所有功能,但最終設想我可能必須重新實現一些編譯語言的核心例程。 Python是一個原型語言,但是Python在允許函數,函子,對象傳遞給函數和方法方面非常自由,但我懷疑C或Fortran也是如此。 。在編譯之前用Python代碼進行原型設計

我應該知道如何設計我設想的函數/類,它們必須與編譯語言接口?這些潛在問題有多少由cTypes,bgen,SWIG,Boost.Python,CythonPython SIP等庫處理?對於這個特定的用例(適配庫),我想象允許用戶定義數學函數(Guassian,Lorentzian等)作爲Python函數,然後可以通過編譯代碼擬合庫來解釋。傳遞和返回數組也是必不可少的。

回答

35

最後一個問題,我可以真正把價值的答案:)。

我已經調查了f2py,boost.python,swig,cython和pyrex以供我的工作(光學測量技術博士學位)。我廣泛使用swig,boost.python一些和pyrex和cython很多。我也用ctypes。這是我的故障:

免責聲明:這是我的個人經驗。我沒有參與任何這些項目。

swig: 與C++不兼容。它應該,但是在鏈接步驟中名稱損壞的問題對於我來說是一個令人頭疼的問題,因爲它在Mac OS X上是非常令人頭痛的。如果你有C代碼並且希望它與python接口,那麼這是一個很好的解決方案。我爲我的需要包裝了GTS,並且需要編寫基本可以連接的C共享庫。我不會推薦它。

ctypes的: 我寫了使用ctypes的一個libdc1394(IEEE相機庫)的包裝,這是一個非常straigtforward經驗。你可以在https://launchpad.net/pydc1394找到代碼。將頭文件轉換爲Python代碼是很多工作,但是一切工作都可靠。如果你想連接外部庫,這是一個好方法。 Ctypes也是Python的stdlib,所以每個人都可以立即使用你的代碼。這也是一個很好的方式來快速使用python中的新庫。我可以推薦它連接到外部庫。

Boost.Python:非常愉快。如果你已經有了你自己想要在python中使用的C++代碼,那就去做吧。以這種方式將C++類結構轉換爲python類結構非常容易。我推薦它,如果你有python需要的C++代碼。

耐熱玻璃/用Cython:使用用Cython,不耐熱玻璃。期。 Cython更先進,更愉快使用。如今,我所做的一切都是用我用SWIG或Ctypes做的cython。如果你的Python代碼運行速度太慢,這也是最好的方法。這個過程非常奇妙:你將你的python模塊轉換成cython模塊,構建它們並保持分析和優化,就像仍然是python一樣(不需要改變工具)。然後,您可以應用盡可能多(或儘可能少)的C代碼與Python代碼混合。這要比使用C重寫應用程序的整個部分要快得多。你只重寫內部循環。

計時:ctypes具有最高的通話開銷(〜700ns),其次是boost.python(322ns),然後直接通過swig(290ns)。 Cython具有最低的通話開銷(124ns)和花費時間的最佳反饋(cProfile支持!)。數字來自我的方框,調用一個簡單的函數,它從交互式shell中返回一個整數;因此,模塊導入開銷不是定時的,只有函數調用開銷。因此,通過分析和使用cython來快速獲得python代碼是最簡單和最有成效的。

摘要:對於你的問題,使用Cython;)。我希望這個概要對一些人有用。我會很樂意回答剩下的問題。


編輯:我忘記提及:進行數值的目的(即,連接到NumPy的)使用用Cython;他們支持它(因爲他們基本上爲此開發了cython)。所以這應該是你的決定的另一個+1。

+0

非常有價值的概述,謝謝。你有暴露高度模板化C++的經驗嗎?我知道boost方法是模板元編程,但他們是否真的支持暴露模板元編程庫?此外,在過去18個月中對該清單所做的任何更改? – daspostloch 2011-04-20 09:06:08

1

根據我的經驗,有兩種簡單的方法可以從Python代碼調用C代碼。還有其他方法,所有這些方法都比較煩人和/或冗長。

第一個也是最簡單的方法是將一堆C代碼編譯爲單獨的共享庫,然後使用ctypes在該庫中調用函數。不幸的是,傳遞除基本數據類型之外的任何東西都是不重要的。

第二種最簡單的方法是在C中編寫一個Python模塊,然後調用該模塊中的函數。你可以將任何你想要的東西傳遞給這些C函數,而不必跳過任何箍環。從這些C函數調用Python函數或方法很容易,如下所述:https://docs.python.org/extending/extending.html#calling-python-functions-from-c

我沒有足夠的SWIG經驗來提供智能註釋。雖然可以通過ctypes將自定義Python對象傳遞給C函數,或者在C中定義新的Python類,但這些操作很煩人而且冗長,我建議採用上述兩種方法之一。

6

規劃最終轉換爲編譯代碼的最佳方法是將性能敏感部分寫爲functional style(無狀態且無副作用)中的簡單函數模塊,該模塊接受並返回基本數據類型。

這將提供從您的Python原型代碼到最終編譯代碼的一對一映射,並且可以讓您輕鬆使用ctypes並避免一大堆令人頭痛的問題。

對於峯值擬合,你幾乎肯定需要使用數組,這會使事情變得複雜一點,但仍然非常適合ctypes。

如果你真的想使用更復雜的數據結構或修改傳遞的參數,SWIGPython's standard C-extension interface會讓你做你想做的事情,但有一些麻煩。

對於您正在做的事情,您可能還想查看NumPy,這可能會執行一些您想要推送給C的工作,以及提供some additional help in moving data back and forth between Python and C

10

我沒有使用SWIG或SIP,但我發現編寫Python包裝與boost.python是非常強大和相對容易使用。

我不清楚你在C/C++和Python之間傳遞類型的要求是什麼,但是你可以通過將C++類型暴露給python或者通過使用C++ API的通用boost::python::object參數。您還可以註冊轉換器來自動將python類型轉換爲C++類型,反之亦然。

如果你打算使用boost.python,tutorial是一個很好的開始。

我已經實現了一些與你所需要的東西有點類似的東西。我有一個C++函數 接受一個python函數和一個圖像作爲參數,並將python函數應用於圖像中的每個像素。

Image* unary(boost::python::object op, Image& im) 
{ 
    Image* out = new Image(im.width(), im.height(), im.channels()); 
    for(unsigned int i=0; i<im.size(); i++) 
    { 
     (*out)[i] == extract<float>(op(im[i])); 
    } 
    return out; 
} 

在這種情況下,圖像是一個C++暴露於蟒(與浮子像素的圖像)對象,並且op是一個Python定義函數(或真與_ _呼叫_ _屬性的任何蟒對象)。然後,您可以使用此功能如下(假設一元位於還包含圖片和負載功能稱爲圖像):

import image 
im = image.load('somefile.tiff') 
double_im = image.unary(lambda x: 2.0*x, im) 

至於使用數組與提升,我個人沒有這樣做,而是我知道使用boost來將數組公開給Python的功能可用 - this可能會有所幫助。

4

f2pynumpy的一部分)是用於包裝C/Fortran數字運算代碼的SWIG和boost.python的一個簡單替代方案。

0

Python在允許函數,函子,對象傳遞給函數和方法時非常自由,但我懷疑C或Fortran也是如此。

在C中,你不能將一個函數作爲參數傳遞給一個函數,但是你可以傳遞一個函數指針,這個函數也是一個很好的函數。

我不知道當你嘗試整合C和Python代碼時,這會有多大幫助,但我只想澄清一個誤解。

0

除了上述的工具,我可以推薦使用Pyrex (用於創建Python擴展模塊)或Psyco(作爲JIT編譯器爲Python)。

相關問題