当Deferreds引发错误时,Python DeferredList回调报告成功

时间:2014-04-28 21:32:26

标签: python asynchronous twisted

我有以下简单的脚本:

#!/usr/bin/env python
from twisted.internet import defer             
from twisted.web.client import getPage, reactor

def success(results):
  print 'success'              

def error(results):
  print 'error'         

def finished(results):
  print 'finished', results

tasks = []

d = getPage('thiswontwork').addCallback(success).addErrback(error)
tasks.append(d)

dl = defer.DeferredList(tasks)
dl.addCallback(finished)

reactor.run()

产生以下输出:

error
finished [(True, None)]

我希望这个错误任务返回false,因为getPages任务失败并调用它的错误回调。任何人都可以解释这种行为吗?

2 个答案:

答案 0 :(得分:4)

让我添加一个超出您选择答案的想法:

在您的问题中,您打印了调用延迟(列表)回调(finished)的参数,并且您注意到您希望它是false(因为之前发生的错误)

这种期望表明你对延迟的思考会让你感到困惑later

让我看看我能否打破这一点......

(这里有很多细节和巧妙的东西,我会尽我所能)

延期是:

  1. 函数回调队列
  2. 对于每个步骤'在队列中存储了callbackerrback函数回调
    • addCallbacks(注意其复数形式)允许您一次添加回调和错误回复
    • addCallback添加一个回调(并将errback设置为跳转到队列中的下一个条目)
    • addErrback添加了一个errback(并设置回调以跳转到队列中的下一个条目)
    • addBoth添加一个函数作为errback和回调(...这意味着它需要弄清楚为什么通过arg调用它被调用
  3. krondo's part 7绘图:( ...扭曲的文档也有good drawing

    Krondo's deferred drawing

    如果将某个函数添加到延迟为callback且延迟已达到其“触发”的点。在此之前的步骤成功返回,延迟时将上一个成功函数的返回值传递给callback中定义的函数。

    如果将某个函数添加到延迟为errback且延迟已达到其“触发”的点。上一步返回Failure对象(或引发异常,将其转换为Failure对象),然后将使用该errback对象调用Failure 注意! 如果errback没有返回Failure,则延迟将转回调用callback链,不是错误!

    Krondo's part 9绘制:

    Connections between callbacks and errorbacks

    虽然这可能看起来像是一个让人烦恼的事情,但是它可以让你实现像延迟错误恢复这样的事情,这可能真的很有用(而且在协议设计中并非罕见)

    I.E :(来自Krondo's part 9):

    krondo's drawing of a deferred recovering from an error

    把这一切都放在一起,你想到的错误就是"我希望这个错误任务能够返回错误的"是finished不被任何类型的错误任务调用,它被延迟调用,并且它只调用成功(因为它仅作为callback加载到errback而不是finished

    如果您已将errback功能同时加载为callbackaddBoth(可能是通过Failure),并且您已按照回答建议转发回复通过返回finished对象的错误的状态,您的False函数在技术上仍然无法通过 Failure!它会收到一个{{1}}对象。

    ......就像我说的那样,在这个东西中有很多巧妙的......

    如果你发现任何这些有用(......或者即使你不是 - 我不是作家的好人),你真的应该挖掘Krondo's twisted introduction。我认为在完成该指南后,你会发现很多这些快照成为焦点。

答案 1 :(得分:3)

如果您没有从errback返回错误/异常,则认为该错误已被处理。尝试更改error()功能:

def error(results):
    print 'error'
    return results

这样会返回错误(results),然后DeferredList会看到错误并调用errback