<?xml version="1.0"?>css
<html lang="en" xml:lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta name="generator" content="HTML Tidy for Windows (vers 1st November 2003), see www.w3.org" /> <title>Twisted Documentation: Deferreds are beautiful! (A Tutorial)</title> <link href="../howto/stylesheet.css" type="text/css" rel="stylesheet" /> </head> <body bgcolor="white"> <h1 class="title">Deferreds are beautiful! (A Tutorial)</h1> <div class="toc"> <ol> <li><a href="#auto0">Introduction</a></li> <li><a href="#auto1">A simple example</a></li> <li><a href="#auto2">Errbacks</a></li> <li style="list-style: none"> <ul> <li><a href="#auto3">Failure in requested operation</a></li> <li><a href="#auto4">Exceptions raised in callbacks</a></li> <li><a href="#auto5">Exceptions will only be handled by errbacks</a></li> <li><a href="#auto6">Handling an exception and continuing on</a></li> </ul> </li> <li><a href="#auto7">addBoth: the deferred version of finally</a></li> <li><a href="#auto8">addCallbacks: decision making based on previous success or failure</a></li> <li><a href="#auto9">Hints, tips, common mistakes, and miscellaney</a></li> <li style="list-style: none"> <ul> <li><a href="#auto10">The deferred callback chain is stateful</a></li> <li><a href="#auto11">Don't call .callback() on deferreds you didn't create!</a></li> <li><a href="#auto12">Callbacks can return deferreds</a></li> </ul> </li> <li><a href="#auto13">Conclusion</a></li> </ol> </div> <div class="content"> <h2>Introduction<a name="auto0" id="auto0"></a></h2> <p>Deferreds are quite possibly the single most confusing topic that a newcomer to Twisted has to deal with. I am going to forgo the normal talk about what deferreds are, what they aren't, and why they're used in Twisted. Instead, I'm going show you the logic behind what they <strong>do</strong>.</p> <p>對Twisted的新手來講,deferred或許是最令他們感到困惑的東西。我準備先把「它是什麼」, 「不是什麼」以及「爲何Twisted必需要用它」之類的普通問題先放一放。這裏我先給你介紹一下它的工做原理。</p>html
<p>A deferred allows you to encapsulate the logic that you'd normally use to make a series of function calls after receiving a result into a single object. In the examples that follow, I'll first show you what's going to go on behind the scenes in the deferred chain, then show you the deferred API calls that set up that chain. All of these examples are runnable code, so feel free to play around with them.</p> <p>deferred的做用是,能讓你把一般狀況下,當一個對象收到一個結果以後會產生一系列方法調用的處理邏輯封裝起來。下面咱們會舉一些例子,我會告訴你在deferred鏈背後究竟發生了些什麼。此外我還會演示怎樣用deferred API來構建這個鏈。這些代碼都能運行,因此儘管試吧。</p>python
<h2>A simple example<a name="auto1" id="auto1"></a></h2>express
First, a simple example so that we have something to talk about:app
<div class="py-listing"> <pre> <span class="py-src-comment">#!/usr/bin/python2.3 </span> <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span> <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span>, <span class="py-src-variable">util</span>ide
<span class="py-src-string">""" here we have the simplest case, a single callback and a single errback """</span>函數
<span class="py-src-variable">num</span> = <span class="py-src-number">0</span> <span class="py-src-keyword">def</span> <span class="py-src-identifier">handleFailure</span>(<span class="py-src-parameter">f</span>): <span class="py-src-keyword">print</span> <span class="py-src-string">"errback"</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"we got an exception: %s"</span> % (<span class="py-src-variable">f</span>.<span class="py-src-variable">getTraceback</span>(),) <span class="py-src-variable">f</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>)oop
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleResult</span>(<span class="py-src-parameter">result</span>): <span class="py-src-keyword">global</span> <span class="py-src-variable">num</span>; <span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,) <span class="py-src-keyword">return</span> <span class="py-src-string">"yay! handleResult was successful!"</span>ui
<span class="py-src-keyword">def</span> <span class="py-src-identifier">behindTheScenes</span>(<span class="py-src-parameter">result</span>): <span class="py-src-comment"># equivalent to d.callback(result) </span> <span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">pass</span>this
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">pass</span> <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">handleFailure</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample</span>(): <span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>() <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">"success"</span>)
<span class="py-src-keyword">if</span> <span class="py-src-variable">name</span> == <span class="py-src-string">'main'</span>: <span class="py-src-variable">behindTheScenes</span>(<span class="py-src-string">"success"</span>) <span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span> <span class="py-src-keyword">global</span> <span class="py-src-variable">num</span>; <span class="py-src-variable">num</span> = <span class="py-src-number">0</span> <span class="py-src-variable">deferredExample</span>() </pre>
<div class="caption">Source listing - <a href="../listings/deferred/deferred_ex.py"><span class="filename">../listings/deferred/deferred_ex.py</span></a></div> </div> <p>And the output: (since both methods in the example produce the same output, it will only be shown once.)</p> <p>輸出以下:(鑑於兩次調用的輸出是相同的,這裏就只打印一次了。)</p>
<pre> callback 1 got result: success </pre>
<p>Here we have the simplest case. A deferred with a single callback and a single errback. Normally, a function would create a deferred and hand it back to you when you request an operation that needs to wait for an event for completion. The object you called then does <code>d.callback(result)</code> when the results are in.</p>
<p>這是最簡單的例子。只帶一個callback和一個errback的defrred。一般你會建一個會返回deferred的函數,而後當你發出一個須要等一段時間才能結束的請求時,你就能夠調用這個方法會獲取一個deferred。等到結果出來了,你再用<code>d.callback(result)</code>。</p>
<p>The thing to notice is that there is only one result that is passed from method to method, and that the result returned from a method is the argument to the next method in the chain. In case of an exception, result is set to an instance of <code base="twisted.python.failure" class="API">Failure</code> that describes the exception.</p>
<p>值得注意的是,全部方法都只能傳一個參數,在這個鏈裏前一個方法的返回值就是後一個方法的參數。萬一碰到異常,twisted就會把返回值設成相應的<code base="twisted.python.failure" class="API">Failure</code>實例。</p>
<h2>Errbacks<a name="auto2" id="auto2"></a></h2> <h3>Failure in requested operation<a name="auto3" id="auto3"></a></h3> <h3>操做請求失敗了</h3>
<p>Things don't always go as planned, and sometimes the function that returned the deferred needs to alert the callback chain that an error has occurred.</p> <p>事情不會老是按着計劃走,有時你得在函數裏設計好,萬一發生了錯誤,callback鏈該作什麼調整。</p> <div class="py-listing"> <pre> <span class="py-src-comment">#!/usr/bin/python2.3 </span> <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span> <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span>, <span class="py-src-variable">util</span>
<span class="py-src-string">""" this example is analagous to a function calling .errback(failure) """</span>
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>): <span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleFailure</span>(<span class="py-src-parameter">f</span>): <span class="py-src-keyword">print</span> <span class="py-src-string">"errback"</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"we got an exception: %s"</span> % (<span class="py-src-variable">f</span>.<span class="py-src-variable">getTraceback</span>(),) <span class="py-src-variable">f</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>)
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleResult</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,) <span class="py-src-keyword">return</span> <span class="py-src-string">"yay! handleResult was successful!"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">failAtHandlingResult</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tabout to raise exception"</span> <span class="py-src-keyword">raise</span> <span class="py-src-variable">RuntimeError</span>, <span class="py-src-string">"whoops! we encountered an error"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">behindTheScenes</span>(<span class="py-src-parameter">result</span>): <span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">pass</span>
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">pass</span> <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">handleFailure</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>() <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">failAtHandlingResult</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
<span class="py-src-variable">d</span>.<span class="py-src-variable">errback</span>(<span class="py-src-variable">result</span>)
<span class="py-src-keyword">if</span> <span class="py-src-variable">name</span> == <span class="py-src-string">'main'</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">None</span> <span class="py-src-keyword">try</span>: <span class="py-src-keyword">raise</span> <span class="py-src-variable">RuntimeError</span>, <span class="py-src-string">"doh! failure!"</span> <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-variable">behindTheScenes</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span> <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span> <span class="py-src-variable">deferredExample</span>(<span class="py-src-variable">result</span>) </pre>
<div class="caption">Source listing - <a href="../listings/deferred/deferred_ex1a.py"><span class="filename">../listings/deferred/deferred_ex1a.py</span></a></div> </div> <pre> errback we got an exception: Traceback (most recent call last): --- exception caught here --- File "deferred_ex1a.py", line 73, in ? raise RuntimeError, "*doh*! failure!" exceptions.RuntimeError: *doh*! failure! </pre> <p>The important thing to note (as it will come up again in later examples) is that the callback isn't touched, the failure goes right to the errback. Also note that the errback trap()s the expected exception type. If you don't trap the exception, an error will be logged when the deferred is garbage-collected.</p> <p>值得注意的是(由於在後面的例子中還會碰到),callback根本沒機會發言,failure直接走到errback那裏去了。一樣errback trap()(捕捉到了)它所但願獲得的異常。若是你沒有捕獲異常,那麼當垃圾回收器回收deferred的時候,它就會往日誌裏寫一條error記錄。</p>
<h3>Exceptions raised in callbacks<a name="auto4" id="auto4"></a></h3> <h3>callback拋出了異常</h3> <p>Now let's see what happens when <em>our callback</em> raises an exception</p> <p>如今咱們來看看當<em>callback</em>拋出異常的時候會發生些什麼。</p> <div class="py-listing"> <pre> <span class="py-src-comment">#!/usr/bin/python2.3 </span> <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span> <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span>, <span class="py-src-variable">util</span>
<span class="py-src-string">""" here we have a slightly more involved case. The deferred is called back with a result. the first callback returns a value, the second callback, however raises an exception, which is handled by the errback. """</span>
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>): <span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleFailure</span>(<span class="py-src-parameter">f</span>): <span class="py-src-keyword">print</span> <span class="py-src-string">"errback"</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"we got an exception: %s"</span> % (<span class="py-src-variable">f</span>.<span class="py-src-variable">getTraceback</span>(),) <span class="py-src-variable">f</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>)
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleResult</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,) <span class="py-src-keyword">return</span> <span class="py-src-string">"yay! handleResult was successful!"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">failAtHandlingResult</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tabout to raise exception"</span> <span class="py-src-keyword">raise</span> <span class="py-src-variable">RuntimeError</span>, <span class="py-src-string">"whoops! we encountered an error"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">behindTheScenes</span>(<span class="py-src-parameter">result</span>): <span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">pass</span>
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failAtHandlingResult</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">pass</span> <span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">pass</span> <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">handleFailure</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample</span>(): <span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>() <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">failAtHandlingResult</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">"success"</span>)
<span class="py-src-keyword">if</span> <span class="py-src-variable">name</span> == <span class="py-src-string">'main'</span>: <span class="py-src-variable">behindTheScenes</span>(<span class="py-src-string">"success"</span>) <span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span> <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span> <span class="py-src-variable">deferredExample</span>() </pre>
<div class="caption">Source listing - <a href="../listings/deferred/deferred_ex1b.py"><span class="filename">../listings/deferred/deferred_ex1b.py</span></a></div> </div> <p>And the output: (note, tracebacks will be edited slightly to conserve space)</p> <pre> callback 1 got result: success callback 2 got result: yay! handleResult was successful! about to raise exception errback we got an exception: Traceback (most recent call last): --- <exception caught here> --- File "/home/slyphon/Projects/Twisted/trunk/twisted/internet/defer.py", line 326, in _runCallbacks self.result = callback(self.result, *args, **kw) File "./deferred_ex1.py", line 32, in failAtHandlingResult raise RuntimeError, "whoops! we encountered an error" exceptions.RuntimeError: whoops! we encountered an error </pre> <p>If your callback raises an exception, the next method to be called will be the next errback in your chain.</p> <p>若是callback拋出了異常,那麼下一個調用的將是跟在這個callback以後的第一個errback。</p>
<h3>Exceptions will only be handled by errbacks<a name="auto5" id="auto5"></a></h3> <h3>只有errback纔會去管Exception</h3>
<p>If a callback raises an exception the next method to be called will be next errback in the chain. If the chain is started off with a failure, the first method to be called will be the first errback.</p> <p>若是callback拋出了異常,那麼下一個調用的將是跟在這個callabck後面的第一個errback。若是callback鏈一開始就出了錯,那麼它就會調用第一個errback。</p> <div class="py-listing"> <pre> <span class="py-src-comment">#!/usr/bin/python2.3 </span> <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span> <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span>, <span class="py-src-variable">util</span>
<span class="py-src-string">""" this example shows an important concept that many deferred newbies (myself included) have trouble understanding.
when an error occurs in a callback, the first errback after the error occurs will be the next method called. (in the next example we'll see what happens in the 'chain' after an errback)
"""</span>
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>): <span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleFailure</span>(<span class="py-src-parameter">f</span>): <span class="py-src-keyword">print</span> <span class="py-src-string">"errback"</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"we got an exception: %s"</span> % (<span class="py-src-variable">f</span>.<span class="py-src-variable">getTraceback</span>(),) <span class="py-src-variable">f</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>)
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleResult</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,) <span class="py-src-keyword">return</span> <span class="py-src-string">"yay! handleResult was successful!"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">failAtHandlingResult</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tabout to raise exception"</span> <span class="py-src-keyword">raise</span> <span class="py-src-variable">RuntimeError</span>, <span class="py-src-string">"whoops! we encountered an error"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">behindTheScenes</span>(<span class="py-src-parameter">result</span>): <span class="py-src-comment"># equivalent to d.callback(result) </span> <span class="py-src-comment"># now, let's make the error happen in the first callback </span> <span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failAtHandlingResult</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">pass</span>
<span class="py-src-comment"># note: this callback will be skipped because
</span> <span class="py-src-comment"># result is a failure </span> <span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">pass</span>
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">pass</span> <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">handleFailure</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample</span>(): <span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>() <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">failAtHandlingResult</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">"success"</span>)
<span class="py-src-keyword">if</span> <span class="py-src-variable">name</span> == <span class="py-src-string">'main'</span>: <span class="py-src-variable">behindTheScenes</span>(<span class="py-src-string">"success"</span>) <span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span> <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span> <span class="py-src-variable">deferredExample</span>() </pre>
<div class="caption">Source listing - <a href="../listings/deferred/deferred_ex2.py"><span class="filename">../listings/deferred/deferred_ex2.py</span></a></div> </div> <pre> callback 1 got result: success about to raise exception errback we got an exception: Traceback (most recent call last): File "./deferred_ex2.py", line 85, in ? nonDeferredExample("success") --- <exception caught here> --- File "./deferred_ex2.py", line 46, in nonDeferredExample result = failAtHandlingResult(result) File "./deferred_ex2.py", line 35, in failAtHandlingResult raise RuntimeError, "whoops! we encountered an error" exceptions.RuntimeError: whoops! we encountered an error </pre> <p>You can see that our second callback, handleResult was not called because failAtHandlingResult raised an exception</p> <h3>Handling an exception and continuing on<a name="auto6" id="auto6"></a></h3> <h3>處理異常,而後繼續</h3> <p>In this example, we see an errback handle an exception raised in the preceeding callback. Take note that it could just as easily been an exception from <strong>any other</strong> preceeding method. You'll see that after the exception is handled in the errback (i.e. the errback does not return a failure or raise an exception) the chain continues on with the next callback.</p> <p>在這個例子裏,errback將會處理由上一個callback所拋出的同樣。其實這個異常能夠是<strong>任意</strong>一個callback所產生的。你會發現當errback處理完異常以後(比方說errback再也不返回failure或者拋出異常),callback鏈會繼續下一個callback。</p> <div class="py-listing"> <pre> <span class="py-src-comment">#!/usr/bin/python2.3 </span> <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span> <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span>, <span class="py-src-variable">util</span>
<span class="py-src-string">""" now we see how an errback can handle errors. if an errback does not raise an exception, the next callback in the chain will be called
"""</span>
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>): <span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleFailure</span>(<span class="py-src-parameter">f</span>): <span class="py-src-keyword">print</span> <span class="py-src-string">"errback"</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"we got an exception: %s"</span> % (<span class="py-src-variable">f</span>.<span class="py-src-variable">getTraceback</span>(),) <span class="py-src-variable">f</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>) <span class="py-src-keyword">return</span> <span class="py-src-string">"okay, continue on"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleResult</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,) <span class="py-src-keyword">return</span> <span class="py-src-string">"yay! handleResult was successful!"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">failAtHandlingResult</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tabout to raise exception"</span> <span class="py-src-keyword">raise</span> <span class="py-src-variable">RuntimeError</span>, <span class="py-src-string">"whoops! we encountered an error"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">callbackAfterErrback</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
<span class="py-src-keyword">def</span> <span class="py-src-identifier">behindTheScenes</span>(<span class="py-src-parameter">result</span>): <span class="py-src-comment"># equivalent to d.callback(result) </span> <span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">pass</span>
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failAtHandlingResult</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">pass</span> <span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">pass</span> <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">handleFailure</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">callbackAfterErrback</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">pass</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample</span>(): <span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>() <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">failAtHandlingResult</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">callbackAfterErrback</span>)
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">"success"</span>)
<span class="py-src-keyword">if</span> <span class="py-src-variable">name</span> == <span class="py-src-string">'main'</span>: <span class="py-src-variable">behindTheScenes</span>(<span class="py-src-string">"success"</span>) <span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span> <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span> <span class="py-src-variable">deferredExample</span>() </pre>
<div class="caption">Source listing - <a href="../listings/deferred/deferred_ex3.py"><span class="filename">../listings/deferred/deferred_ex3.py</span></a></div> </div> <pre> callback 1 got result: success about to raise exception errback we got an exception: Traceback (most recent call last): --- <exception caught here> --- File "/home/slyphon/Projects/Twisted/trunk/twisted/internet/defer.py", line 326, in _runCallbacks self.result = callback(self.result, *args, **kw) File "./deferred_ex2.py", line 35, in failAtHandlingResult raise RuntimeError, "whoops! we encountered an error" exceptions.RuntimeError: whoops! we encountered an error </pre> <h2>addBoth: the deferred version of <em>finally</em><a name="auto7" id="auto7"></a></h2> <h2>addBoth:deferred版的<em>finally</em></h2> <p>Now we see how deferreds do <strong>finally</strong>, with .addBoth. The callback that gets added as addBoth will be called if the result is a failure or non-failure. We'll also see in this example, that our doThisNoMatterWhat() method follows a common idiom in deferred callbacks by acting as a passthru, returning the value that it received to allow processing the chain to continue, but appearing transparent in terms of the result.</p> <p>如今咱們來看看deferred是怎樣實現<strong>finally</strong>的,答案就是.addBoth。無論參數是否是failure,addBoth所加載的callback都會被調用。此外咱們還會看的,doThisNoMatterWhat()方法以充當passthru的方式遵照了deferred的callback約定。它將收到的數據原封不動地發出去,這樣處理鏈就能繼續下去了。對數據來講,它是徹底透明的。</p>
<div class="py-listing"> <pre> <span class="py-src-comment">#!/usr/bin/python2.3 </span> <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span> <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span>, <span class="py-src-variable">util</span>
<span class="py-src-string">""" now we'll see what happens when you use 'addBoth'
"""</span>
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>): <span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleFailure</span>(<span class="py-src-parameter">f</span>): <span class="py-src-keyword">print</span> <span class="py-src-string">"errback"</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"we got an exception: %s"</span> % (<span class="py-src-variable">f</span>.<span class="py-src-variable">getTraceback</span>(),) <span class="py-src-variable">f</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>) <span class="py-src-keyword">return</span> <span class="py-src-string">"okay, continue on"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleResult</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,) <span class="py-src-keyword">return</span> <span class="py-src-string">"yay! handleResult was successful!"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">failAtHandlingResult</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tabout to raise exception"</span> <span class="py-src-keyword">raise</span> <span class="py-src-variable">RuntimeError</span>, <span class="py-src-string">"whoops! we encountered an error"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">doThisNoMatterWhat</span>(<span class="py-src-parameter">arg</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"both %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot argument %r"</span> % (<span class="py-src-variable">arg</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tdoing something very important"</span> <span class="py-src-comment"># we pass the argument we received to the next phase here </span> <span class="py-src-keyword">return</span> <span class="py-src-variable">arg</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">behindTheScenes</span>(<span class="py-src-parameter">result</span>): <span class="py-src-comment"># equivalent to d.callback(result) </span> <span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">pass</span>
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failAtHandlingResult</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">pass</span> <span class="py-src-comment"># ---- this is equivalent to addBoth(doThisNoMatterWhat)
</span> <span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">doThisNoMatterWhat</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">doThisNoMatterWhat</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">pass</span> <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">handleFailure</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample</span>(): <span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>() <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">failAtHandlingResult</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">addBoth</span>(<span class="py-src-variable">doThisNoMatterWhat</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">"success"</span>)
<span class="py-src-keyword">if</span> <span class="py-src-variable">name</span> == <span class="py-src-string">'main'</span>: <span class="py-src-variable">behindTheScenes</span>(<span class="py-src-string">"success"</span>) <span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span> <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span> <span class="py-src-variable">deferredExample</span>() </pre>
<div class="caption">Source listing - <a href="../listings/deferred/deferred_ex4.py"><span class="filename">../listings/deferred/deferred_ex4.py</span></a></div> </div> <pre> callback 1 got result: success callback 2 got result: yay! handleResult was successful! about to raise exception both 3 got argument <twisted.python.failure.Failure exceptions.RuntimeError> doing something very important errback we got an exception: Traceback (most recent call last): --- <exception caught here> --- File "/home/slyphon/Projects/Twisted/trunk/twisted/internet/defer.py", line 326, in _runCallbacks self.result = callback(self.result, *args, **kw) File "./deferred_ex4.py", line 32, in failAtHandlingResult raise RuntimeError, "whoops! we encountered an error" exceptions.RuntimeError: whoops! we encountered an error </pre> <p>You can see that the errback is called, (and consequently, the failure is trapped). This is because doThisNoMatterWhat method returned the value it received, a failure.</p> <h2>addCallbacks: decision making based on previous success or failure<a name="auto8" id="auto8"></a></h2> <h2>addCallbacks: 根據前面的運行結果加載callback</h2> <p>As we've been seeing in the examples, the callback is a pair of callback/errback. Using addCallback or addErrback is actually a special case where one of the pair is a pass statement. If you want to make a decision based on whether or not the previous result in the chain was a failure or not (which is very rare, but included here for completeness), you use addCallbacks. Note that this is <strong>not</strong> the same thing as an addCallback followed by an addErrback.</p> <p>正如咱們前面所講的,回調函數是一組callback/errback。不管是addCallback仍是addErrback其實都是特例,由於在加載一個函數的同時,咱們也pass了另外一個另外一個函數。若是你想根據前一次調用是否成功來判斷該加載哪一個函數(這種狀況十分罕見,不過出於完整性的考慮,twisted也提供了),那麼可使用addCallbacks。注意,這和addCallback以後再addErrback<strong>是兩碼事</strong></p>
<div class="py-listing"> <pre> <span class="py-src-comment">#!/usr/bin/python2.3 </span> <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span> <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span>, <span class="py-src-variable">util</span>
<span class="py-src-string">""" now comes the more nuanced addCallbacks, which allows us to make a yes/no (branching) decision based on whether the result at a given point is a failure or not.
"""</span>
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>): <span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleFailure</span>(<span class="py-src-parameter">f</span>): <span class="py-src-keyword">print</span> <span class="py-src-string">"errback"</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"we got an exception: %s"</span> % (<span class="py-src-variable">f</span>.<span class="py-src-variable">getTraceback</span>(),) <span class="py-src-variable">f</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>) <span class="py-src-keyword">return</span> <span class="py-src-string">"okay, continue on"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleResult</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,) <span class="py-src-keyword">return</span> <span class="py-src-string">"yay! handleResult was successful!"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">failAtHandlingResult</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tabout to raise exception"</span> <span class="py-src-keyword">raise</span> <span class="py-src-variable">RuntimeError</span>, <span class="py-src-string">"whoops! we encountered an error"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">yesDecision</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"yes decision %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\twasn't a failure, so we can plow ahead"</span> <span class="py-src-keyword">return</span> <span class="py-src-string">"go ahead!"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">noDecision</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-variable">result</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>) <span class="py-src-keyword">print</span> <span class="py-src-string">"no decision %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tdoh! a failure! quick! damage control!"</span> <span class="py-src-keyword">return</span> <span class="py-src-string">"damage control successful!"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">behindTheScenes</span>(<span class="py-src-parameter">result</span>):
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failAtHandlingResult</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">pass</span> <span class="py-src-comment"># this is equivalent to addCallbacks(yesDecision, noDecision)
</span> <span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">yesDecision</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">noDecision</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">pass</span> <span class="py-src-comment"># this is equivalent to addCallbacks(yesDecision, noDecision)
</span> <span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">yesDecision</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">noDecision</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">pass</span> <span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">pass</span> <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">handleFailure</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample</span>(): <span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>() <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">failAtHandlingResult</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallbacks</span>(<span class="py-src-variable">yesDecision</span>, <span class="py-src-variable">noDecision</span>) <span class="py-src-comment"># noDecision will be called</span> <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>) <span class="py-src-comment"># - A -</span> <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallbacks</span>(<span class="py-src-variable">yesDecision</span>, <span class="py-src-variable">noDecision</span>) <span class="py-src-comment"># yesDecision will be called</span> <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">"success"</span>)
<span class="py-src-keyword">if</span> <span class="py-src-variable">name</span> == <span class="py-src-string">'main'</span>: <span class="py-src-variable">behindTheScenes</span>(<span class="py-src-string">"success"</span>) <span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span> <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span> <span class="py-src-variable">deferredExample</span>() </pre>
<div class="caption">Source listing - <a href="../listings/deferred/deferred_ex5.py"><span class="filename">../listings/deferred/deferred_ex5.py</span></a></div> </div> <pre> callback 1 got result: success about to raise exception no decision 2 *doh*! a failure! quick! damage control! callback 3 got result: damage control successful! yes decision 4 wasn't a failure, so we can plow ahead callback 5 got result: go ahead! </pre> <p>Notice that our errback is never called. The noDecision method returns a non-failure so processing continues with the next callback. If we wanted to skip the callback at "- A -" because of the error, but do some kind of processing in response to the error, we would have used a passthru, and returned the failure we received, as we see in this next example:</p> <p>注意,咱們的errback一直沒被調用。noDecision方法返回了一個非failure的值,因此處理連接下來調用的是callback。若是你想跳過位於"- A -"的callback,但又不想放過錯誤,那麼你就得用passthru把收到的failure再發出去。這就是下一段例程所演示的:</p> <div class="py-listing"> <pre> <span class="py-src-comment">#!/usr/bin/python2.3 </span> <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span> <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span>, <span class="py-src-variable">util</span>
<span class="py-src-string">""" now comes the more nuanced addCallbacks, which allows us to make a yes/no (branching) decision based on whether the result at a given point is a failure or not.
here, we return the failure from noDecisionPassthru, the errback argument to the first addCallbacks method invocation, and see what happens
"""</span>
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>): <span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleFailure</span>(<span class="py-src-parameter">f</span>): <span class="py-src-keyword">print</span> <span class="py-src-string">"errback"</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"we got an exception: %s"</span> % (<span class="py-src-variable">f</span>.<span class="py-src-variable">getTraceback</span>(),) <span class="py-src-variable">f</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>) <span class="py-src-keyword">return</span> <span class="py-src-string">"okay, continue on"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleResult</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,) <span class="py-src-keyword">return</span> <span class="py-src-string">"yay! handleResult was successful!"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">failAtHandlingResult</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tabout to raise exception"</span> <span class="py-src-keyword">raise</span> <span class="py-src-variable">RuntimeError</span>, <span class="py-src-string">"whoops! we encountered an error"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">yesDecision</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"yes decision %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\twasn't a failure, so we can plow ahead"</span> <span class="py-src-keyword">return</span> <span class="py-src-string">"go ahead!"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">noDecision</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-variable">result</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>) <span class="py-src-keyword">print</span> <span class="py-src-string">"no decision %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tdoh! a failure! quick! damage control!"</span> <span class="py-src-keyword">return</span> <span class="py-src-string">"damage control successful!"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">noDecisionPassthru</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"no decision %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tdoh! a failure! don't know what to do, returning failure!"</span> <span class="py-src-keyword">return</span> <span class="py-src-variable">result</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">behindTheScenes</span>(<span class="py-src-parameter">result</span>):
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failAtHandlingResult</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">pass</span> <span class="py-src-comment"># this is equivalent to addCallbacks(yesDecision, noDecision)
</span> <span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">yesDecision</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">noDecisionPassthru</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">pass</span> <span class="py-src-comment"># this is equivalent to addCallbacks(yesDecision, noDecision)
</span> <span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">yesDecision</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">noDecision</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>() <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">pass</span> <span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span> <span class="py-src-keyword">pass</span> <span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span> <span class="py-src-keyword">try</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">handleFailure</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">except</span>: <span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample</span>(): <span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>() <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">failAtHandlingResult</span>)
<span class="py-src-comment"># noDecisionPassthru will be called
</span> <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallbacks</span>(<span class="py-src-variable">yesDecision</span>, <span class="py-src-variable">noDecisionPassthru</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>) <span class="py-src-comment"># - A -</span>
<span class="py-src-comment"># noDecision will be called
</span> <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallbacks</span>(<span class="py-src-variable">yesDecision</span>, <span class="py-src-variable">noDecision</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>) <span class="py-src-comment"># - B -</span> <span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">"success"</span>)
<span class="py-src-keyword">if</span> <span class="py-src-variable">name</span> == <span class="py-src-string">'main'</span>: <span class="py-src-variable">behindTheScenes</span>(<span class="py-src-string">"success"</span>) <span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span> <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span> <span class="py-src-variable">deferredExample</span>() </pre>
<div class="caption">Source listing - <a href="../listings/deferred/deferred_ex6.py"><span class="filename">../listings/deferred/deferred_ex6.py</span></a></div> </div> <pre> callback 1 got result: success about to raise exception no decision 2 *doh*! a failure! don't know what to do, returning failure! no decision 3 *doh*! a failure! quick! damage control! callback 4 got result: damage control successful! </pre> <p>Two things to note here. First, "- A -" was skipped, like we wanted it to, and the second thing is that after "- A -", noDecision is called, because <strong>it is the next errback that exists in the chain</strong>. It returns a non-failure, so processing continues with the next callback at "- B -", and the errback at the end of the chain is never called</p> <p>有兩點值得注意。第一,正如咱們所但願的,它跳過了「- A -」,第二,跳過「- A -」以後它調用了noDecision,由於<strong>這是鏈中的下一個errback</strong>。這個errback返回的是一個非failure的值,因此接下來執行的是「- B -」的callback,而最有一個errback是不可能被調到的。</p>
<h2>Hints, tips, common mistakes, and miscellaney<a name="auto9" id="auto9"></a></h2> <h2>提示,技巧,常見錯誤及其它</h2> <h3>The deferred callback chain is stateful<a name="auto10" id="auto10"></a></h3> <h3>deffered的callback鏈是帶狀態的</h3> <p>A deferred that has been called back will call it's addCallback and addErrback methods as appropriate in the order they are added, when they are added. So we see in the following example, deferredExample1 and deferredExample2 are equivalent. The first sets up the processing chain beforehand and then executes it, the other executes the chain as it is being constructed. This is because deferreds are <em>stateful</em>.</p> <p>deferred的回調順序就是addCallback和addErrback的順序。因此咱們看下面這個例子,deferredExample1和deferredExample2是同樣的。第一個先建處理鏈再調用,第二個則一邊建一邊調用。這是由於deferred是<em>帶狀態的</em>。</p>
<div class="py-listing"> <pre> <span class="py-src-comment">#!/usr/bin/python2.3 </span> <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span> <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span>, <span class="py-src-variable">util</span>
<span class="py-src-string">""" The deferred callback chain is stateful, and can be executed before or after all callbacks have been added to the chain """</span>
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>): <span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleFailure</span>(<span class="py-src-parameter">f</span>): <span class="py-src-keyword">print</span> <span class="py-src-string">"errback"</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"we got an exception: %s"</span> % (<span class="py-src-variable">f</span>.<span class="py-src-variable">getTraceback</span>(),) <span class="py-src-variable">f</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>)
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleResult</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,) <span class="py-src-keyword">return</span> <span class="py-src-string">"yay! handleResult was successful!"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">failAtHandlingResult</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tabout to raise exception"</span> <span class="py-src-keyword">raise</span> <span class="py-src-variable">RuntimeError</span>, <span class="py-src-string">"whoops! we encountered an error"</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample1</span>(): <span class="py-src-comment"># this is another common idiom, since all add* methods </span> <span class="py-src-comment"># return the deferred instance, you can just chain your </span> <span class="py-src-comment"># calls to addCallback and addErrback </span> <span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>().<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">failAtHandlingResult</span> ).<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span> ).<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">"success"</span>)
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample2</span>(): <span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>()
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">"success"</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">failAtHandlingResult</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
<span class="py-src-keyword">if</span> <span class="py-src-variable">name</span> == <span class="py-src-string">'main'</span>: <span class="py-src-variable">deferredExample1</span>() <span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span> <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span> <span class="py-src-variable">deferredExample2</span>() </pre>
<div class="caption">Source listing - <a href="../listings/deferred/deferred_ex7.py"><span class="filename">../listings/deferred/deferred_ex7.py</span></a></div> </div> <pre> callback 1 got result: success about to raise exception errback we got an exception: Traceback (most recent call last): --- <exception caught here> --- File "/home/slyphon/Projects/Twisted/trunk/twisted/internet/defer.py", line 326, in _runCallbacks self.result = callback(self.result, *args, **kw) File "./deferred_ex7.py", line 35, in failAtHandlingResult raise RuntimeError, "whoops! we encountered an error" exceptions.RuntimeError: whoops! we encountered an error
callback 1 got result: success about to raise exception errback we got an exception: Traceback (most recent call last): --- <exception caught here> --- File "/home/slyphon/Projects/Twisted/trunk/twisted/internet/defer.py", line 326, in _runCallbacks self.result = callback(self.result, *args, **kw) File "./deferred_ex7.py", line 35, in failAtHandlingResult raise RuntimeError, "whoops! we encountered an error" exceptions.RuntimeError: whoops! we encountered an error </pre>
<p>This example also shows you the common idiom of chaining calls to addCallback and addErrback.</p> <h3>Don't call .callback() on deferreds you didn't create!<a name="auto11" id="auto11"></a></h3> <h3>別去調用還沒建好的deferred的.callback()方法</h3> <p>It is an error to reinvoke deferreds callback or errback method, therefore if you didn't create a deferred, <strong>do not under any circumstances</strong> call its callback or errback. doing so will raise an exception</p> <p>重複調用deferred的callback或errback辦法是一種錯誤,因此若是你還沒建好deferred,那就<strong>別去調用</strong>它的callback或errback,這麼作只會致使錯誤。</p> <h3>Callbacks can return deferreds<a name="auto12" id="auto12"></a></h3> <h3>callback能返回deferred</h3> <p>If you need to call a method that returns a deferred within your callback chain, just return that deferred, and the result of the secondary deferred's processing chain will become the result that gets passed to the next callback of the primary deferreds processing chain</p> <p>若是callback鏈裏的方法會返回deferred,那就讓它返回deferred。這個deferred的處理結果會被看成參數傳給當前這個deferred的下一個callback。</p>
<div class="py-listing"> <pre> <span class="py-src-comment">#!/usr/bin/python2.3 </span> <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span> <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span>, <span class="py-src-variable">util</span>
<span class="py-src-string">""" """</span>
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>): <span class="py-src-variable">num</span> = <span class="py-src-number">0</span> <span class="py-src-variable">let</span> = <span class="py-src-string">'a'</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">incrLet</span>(<span class="py-src-parameter">cls</span>): <span class="py-src-variable">cls</span>.<span class="py-src-variable">let</span> = <span class="py-src-variable">chr</span>(<span class="py-src-variable">ord</span>(<span class="py-src-variable">cls</span>.<span class="py-src-variable">let</span>) + <span class="py-src-number">1</span>) <span class="py-src-variable">incrLet</span> = <span class="py-src-variable">classmethod</span>(<span class="py-src-variable">incrLet</span>)
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleFailure</span>(<span class="py-src-parameter">f</span>): <span class="py-src-keyword">print</span> <span class="py-src-string">"errback"</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"we got an exception: %s"</span> % (<span class="py-src-variable">f</span>.<span class="py-src-variable">getTraceback</span>(),) <span class="py-src-keyword">return</span> <span class="py-src-variable">f</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">subCb_B</span>(<span class="py-src-parameter">result</span>): <span class="py-src-keyword">print</span> <span class="py-src-string">"sub-callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">let</span>,) <span class="py-src-variable">Counter</span>.<span class="py-src-variable">incrLet</span>() <span class="py-src-variable">s</span> = <span class="py-src-string">" beautiful!"</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"\tadding %r to result"</span> % (<span class="py-src-variable">s</span>,) <span class="py-src-variable">result</span> += <span class="py-src-variable">s</span> <span class="py-src-keyword">return</span> <span class="py-src-variable">result</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">subCb_A</span>(<span class="py-src-parameter">result</span>): <span class="py-src-keyword">print</span> <span class="py-src-string">"sub-callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">let</span>,) <span class="py-src-variable">Counter</span>.<span class="py-src-variable">incrLet</span>() <span class="py-src-variable">s</span> = <span class="py-src-string">" are "</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"\tadding %r to result"</span> % (<span class="py-src-variable">s</span>,) <span class="py-src-variable">result</span> += <span class="py-src-variable">s</span> <span class="py-src-keyword">return</span> <span class="py-src-variable">result</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">mainCb_1</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,) <span class="py-src-variable">result</span> += <span class="py-src-string">" Deferreds "</span>
<span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>().<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">subCb_A</span> ).<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">subCb_B</span>) <span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-variable">result</span>) <span class="py-src-keyword">return</span> <span class="py-src-variable">d</span>
<span class="py-src-keyword">def</span> <span class="py-src-identifier">mainCb_2</span>(<span class="py-src-parameter">result</span>): <span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span> <span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,) <span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample</span>(): <span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>().<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">mainCb_1</span> ).<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">mainCb_2</span>)
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">"I hope you'll agree: "</span>)
<span class="py-src-keyword">if</span> <span class="py-src-variable">name</span> == <span class="py-src-string">'main'</span>: <span class="py-src-variable">deferredExample</span>() </pre>
<div class="caption">Source listing - <a href="../listings/deferred/deferred_ex8.py"><span class="filename">../listings/deferred/deferred_ex8.py</span></a></div> </div> <pre> callback 1 got result: I hope you'll agree: sub-callback a adding ' are ' to result sub-callback b adding ' beautiful!' to result callback 2 got result: I hope you'll agree: Deferreds are beautiful! </pre> <h2>Conclusion<a name="auto13" id="auto13"></a></h2> <h2>結論</h2> <p>Deferreds can be confusing, but only because they're so elegant and simple. There is a lot of logical power that can expressed with a deferred's processing chain, and once you see what's going on behind the curtain, it's a lot easier to understand how to make use of what deferreds have to offer.</p> </div> <p><a href="../howto/index.html">Index</a></p> <span class="version">Version: 2.0.0</span> </body> </html>