python開發例項之Python的Twisted框架中Deferred物件的詳細用法與例項
Deferred物件在Twsited框架中用於處理回撥,這對於依靠非同步的Twisted來說十分重要,接下來我們就以例項解析Python的Twisted框架中Deferred物件的用法
Deferred物件結構
Deferred由一系列成對的回撥鏈組成,每一對都包含一個用於處理成功的回撥(callbacks)和一個用於處理錯誤的回撥(errbacks)。初始狀態下,deffereds將由兩個空回撥鏈組成。在向其中添加回調時將總是成對新增。當非同步處理中的結果返回時,Deferred將會啟動並以新增時的順序觸發回撥鏈。
用例項也許更容易說明,首先來看看addCallback:
from twisted.internet.defer import Deferred def myCallback(result): print result d = Deferred() d.addCallback(myCallback) d.callback("Triggering callback.")
執行它將會得到如下結果:
Triggering callback.
上例中建立了一個deffered並利用其addCallback方法註冊一個用於處理成功的回撥。d.callback會啟動deffered並呼叫callback鏈。傳入callback的引數也會被各callback鏈中的第一個函式接收到。
有addCallback,那另一個錯誤的分支,我想也能猜測到了那就是addErrorback,同樣來看個例子:
from twisted.internet.defer import Deferred def myErrback(failure): print failure d = Deferred() d.addErrback(myErrback) d.errback(ValueError("Triggering errback."))
執行它將會得到如下結果:
[Failure instance: Traceback (failure with no frames): <type 'exceptions.ValueError'>: Triggering errback.]
可以看出Twisted會把錯誤封裝在Failure裡。
值得注意的是,在之前提到過註冊回撥總是成對的。在使用d.addCallback和d.addErrorback方法時,我們看似只是添加了一個callback或一個errback。而實際上,為了完成這一級回撥鏈的建立,這些方法還會為另一半註冊一個pass-through。要記住,回撥鏈總是具有相同的長度。如果要分別指定這一級回撥的callback和errback。可以使用d.addCallbacks方法:
d = Deferred() d.addCallbacks(myCallback,myErrback) d.callback("Triggering callback.")
進階示例
接下來就應該來點更為實際的,那就是放進Reactor。先來看一個例子:
from twisted.internet import reactor,defer class HeadlineRetriever(object): def processHeadline(self,headline): if len(headline) > 50: self.d.errback(Exception("The headline ``%s'' is too long!" % (headline,))) else: self.d.callback(headline) def _toHTML(self,result): return "<h1>%s</h1>" % (result,) def getHeadline(self,input): self.d = defer.Deferred() reactor.callLater(1,self.processHeadline,input) self.d.addCallback(self._toHTML) return self.d def printData(result): print result reactor.stop() def printError(failure): print failure reactor.stop() h = HeadlineRetriever() d = h.getHeadline("Breaking News: Twisted Takes us to the Moon!") d.addCallbacks(printData,printError) reactor.run()
上例接收一個標題並對其進行處理,如果標題超長會返回超長的錯誤,否則將其轉為HTML並返回。
因所給的標題少於50個字元,故執行以上程式碼會得到如下返回:
<h1>Breaking News: Twisted Takes us to the Moon!</h1>
有一點值得注意的,上面用到了reactor的callLater方法,它可以用來做定時事件從而模擬一個非同步的請求。
如果我們將標題變得很長,比如說:
h = HeadlineRetriever() d = h.getHeadline("1234567890"*6) d.addCallbacks(printData,printError)
那結果是可以遇見的
[Failure instance: Traceback (failure with no frames):
: The headline ``123456789012345678901234567890123456789012345678901234567890'' is too long!]
我們用圖看一下觸發流程:
- Deferreds中的關鍵之處
- Deferreds將會在呼叫其callback或errback時被觸發;
- Deferreds僅能被觸發一次!如果嘗試多次觸發將會導致AlreadyCalledError異常;
- 第N級callback或errback中的Exceptions將會傳入第N+1級的errback中;如果沒有errback,則會丟擲Unhandled Error。如果第N級callback或errback中沒有丟擲Exception或返回Failure物件,那接下來將會由第N+1級中的callback進行處理;
- callback中返回的結果將會傳入下一級callback,並作為其第一個引數;
- 如果傳入errback的錯誤不是一個Failure物件,那將會被自動包裝一次。
本文主要用例項講解了Python的Twisted框架中Deferred物件的詳細用法,更多關於Python的Twisted框架知識技巧請檢視下面的相關連結