URL:
http://blog.now.in/2010/05/11/build-an-online-radio-station-within-few-minutes-now-in/
我喜歡Python的原因之一就是它的標準函式庫把該有的東西幾乎都包進去了,像是ConfigParser用來讀取設定檔,而logging更是不可缺少的,用來記錄程式的訊息非常好用的函式庫,而且這些函式庫不是只是陽春的玩具,而是功能齊全的基礎,其中logging一個很棒的功能就是將錯誤訊息寄給你,因為通常錯誤發生雖然都可以寫到記錄檔中,但是你有多少時間會去翻記錄檔? 通常程式出錯了,你也不會有認何知覺,將錯誤訊息寄給你的好處就是,一有錯誤你就立刻可以知道,而且少見的錯誤也不會被漏掉,例如有人試圖攻擊你的伺服器,在這過程中如果伺服器發生錯誤會寄信給你,在他成功之前你可能就有機會發現,總之將錯誤訊息寄給自己是很有用的技巧
最棒的就是,要用此功能非常簡單,以下是一個簡單的範例:
# -*- coding: utf8 -*- import logging import logging.handlers rootLogger = logging.getLogger('') rootLogger.setLevel(logging.ERROR) handler = logging.handlers.SMTPHandler( mailhost='smtp.example.com', fromaddr='marines@starcraft2.com', toaddrs='player@starcraft2.com', subject="Houston, We've Got a Problem", credentials=('username', 'password') ) rootLogger.addHandler(handler) log = logging.getLogger(__name__) log.fatal('HELP! We are under attack!')
如果你的SMTP設定沒問題的話,以應該可以收到下面這樣的一封信
就是這麼簡單,這樣一來當你的程式出問題時,你再也不會沒有發覺了
在很久很久以前,想要擴充Python要使用API來包裝成Python可用的模組才可以,面對囉唆的一堆C API是一件痛苦的事,接著,進入了石器時代,人們開始使用工具,出現了SWIG、boost::python等,讓擴充Python變成一件更簡單的事情,但是即使是如此,這還是笨重的方法,產生了笨重的二進制檔,笨重的編譯工作,對於只是要將c語言的library擴充給Python使用而言這還不夠好,接著,終於有了進化,ctypes出現了,人們想說,與其做出pyd來給python使用這種多此一舉的事情,東西就在那裡,dll就在那裡,為何不能直接使用呢? ctypes的目的就是讓Python可以直接操做c語言寫的dll,這是一個大躍進,到了python2.5 ctypes還成為了標準的模組之一,這表示新的時代的到來
相對於熟悉的事物,面對類似性質但是不同的事物時,總難免有多少疑惑,我在一開始也懷疑這樣能做到什麼地步? 但是在看了它的文件後我瞭解到,大部份dll使用ctypes都可以應用得很好,像是我擔心的callback,ctypes一樣可以提供方法來把python的函數包裝成c語言的callback丟給c語言的dll,運作得很好,其中我最擔心的是多緒的問題,因為有些callback是從其它thread呼叫的,因此如果沒考慮到multi-thread問題的話,callback就廢一半了,但是它一樣也考慮很週到,即使是從不同thread呼叫的python callback,也一樣可以運作得很好 舉個例子
DSPPROC = WINFUNCTYPE(None, HDSP, DWORD, c_void_p, DWORD, c_void_p)
在有了c語言函數的原形建立後,我們就可以使用它來包裝python的函數丟給c語言的dll處理
print BASS_Init(-1, 44100, 0, 0, 0) stream = BASS_StreamCreateFile(False, 'c:\\god know.mp3', 0, 0, 0) print stream def dspProc(handle, channel, buffer, length, user): print handle, channel, buffer, length, user cDspProc = DSPPROC(dspProc) print BASS_ChannelSetDSP(stream, cDspProc, None, 0) BASS_ChannelPlay(stream, False) raw_input()
值得注意的是,因為Python有reference counter,也就是說,當沒有變數指向某個物件時,那個物件可能就會被回收,因此如果我們這樣寫
BASS_ChannelSetDSP(stream, DSPPROC(dspProc), None, 0)
Oops,恭喜你,你的程式很可能隨時會當掉,因為暫時的變數在被回收後,那塊記憶體就不再是c語言的函數,裡面可能塞了一些亂七八糟的東西,你的dll一呼叫那函數,遇到了些亂七八糟的東西會當掉也不是什麼奇怪的事,因此寫ctypes時,必須同時使用Python和C語言的觀點來看,舉另一個例子,如果某個C語言的API的文件上寫到,你傳進來的字串它不會copy,只會留著它的指標,在完成之前那個指標應該都還是要為有效的,這時,你就必須在python用一個變數一直保持著reference到產生出來的c語言字串記憶體空間,防止它被回收
除了callback以外,你可能會想到: "阿,那struct和union怎麼辦?" ,ctypes一樣有辦法,以下就是一個例子
class BASS_INFO(Structure): _fields_ = [ ("flags", DWORD), ("hwsize", DWORD), ("hwfree", DWORD), ("freesam", DWORD), ("free3d", DWORD), ("minrate", DWORD), ("maxrate", DWORD), ("eax", BOOL), ("minbuf", DWORD), ("dsver", DWORD), ("latency", DWORD), ("initflags", DWORD), ("speakers", DWORD), ("freq", DWORD), ]
人們總是覺得,事情還可以更好,事情只成功一半,用手寫ctypes是件很痛苦的事情,看著c語言的header檔複製、貼上、修改的無限迴圈,再也沒有比這個還無聊的事情,電腦的發明就是要解決問題,重覆性如此高和有規則的工作不應該浪費保貴的人力,因此,下一步就是c語言header的parser,理想的狀況是,可以自動parse c語言的header然後產生相對應的python ctypes寫的binding module,如果做到這個地步代表了什麼? 這意味著,Python能用的資源,從本來的常見module一下子突然擴大到了所有的c語言寫的library,這是多麼偉大的進步
我使用ctypes的目的在於寫BASS的python binding,BASS是一套audio library,因為它沒提供Python的binding,所以我只好自己寫,在無聊的複製貼上過程中,我有試著想過寫parser來自動化完成我的工作,但是c語言的parser已經複雜到了一個地步,如果要寫出那樣的parser,會比我直接用手寫還來得麻煩,所以就沒有繼續研究
BASS binding運作得很好,有興趣的朋友可以參考看看
七年過去了
七年過去了,Google已經從原本的搜尋引擎變成網路界的龍頭老大,還記得小學時參加查資料比賽,發現有Google這個搜尋引擎,又對它搜尋的速度和準確度感到驚訝
共費0.xx 秒
不起眼的小字在一旁卻讓人感到驚奇,其它入口網站的搜尋引擎,相較之下都對於做搜尋引擎起家的Google相形失色,還記得當年最常用首頁的是奇摩站(Kimo),後來被Yahoo買走,時間過得真快,轉眼間Google已經成為網路的龍頭,為了記念Google十週年,他們還特地製作了刻複版的
http://www.google.com/search2001.html
有興趣可以懷念一下
期待Spam comment
十月 3rd, 2008期待
話說,我一直很期待有Spam comment進來,可是幾天過去了,spam comment還是0,真希望快點有spam comment出現,我真是奇怪 XD
4 comments »
Posted in Uncategorized
Tags: 奇怪 spam comment