Python DeferredList 回调成功但 deferreds 报错
我有一个简单的脚本:
#!/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)]
我本来以为这个错误的任务会返回一个假值,因为getPages这个任务失败了,并且调用了它的错误回调。有人能解释一下这是为什么吗?
2 个回答
如果你没有从你的 errback
函数中返回错误或异常,那么这个错误就会被认为是已经处理过了。试着修改你的 error()
函数:
def error(results):
print 'error'
return results
这样一来,错误(results
)就会被返回,然后 DeferredList
会看到这个错误,并且也会调用它的 errback
函数。
让我补充一点你没有选择的想法:
在你的问题中,你打印了一个参数,这个参数是你的延迟(callback)函数(finished
)被调用时的值,而你注意到你期望它是false
(因为之前发生了错误)
这种期望表明你对延迟的理解可能会让你在后面感到困惑。
让我试着把这个拆开来讲讲……
(这方面有很多细节和微妙之处,我会尽量解释清楚)
延迟是:
- 一个函数回调的队列
- 对于队列中的每一个“步骤”,都有一个
callback
和一个errback
函数回调被存储 addCallbacks
(注意是复数)可以让你同时添加callback和errbackaddCallback
添加一个callback(并将errback设置为跳过队列中的下一个条目)addErrback
添加一个errback(并将callback设置为跳过队列中的下一个条目)addBoth
将一个函数同时作为errback和callback添加(这意味着它需要通过传入的参数来判断自己为什么被调用)
引用Krondo的第7部分:(……Twisted文档也有很好的图示)
如果一个函数作为callback
添加到延迟中,并且延迟已经执行到前一个步骤成功返回的那一刻,延迟会将前一个成功函数的返回值传递给callback
中定义的函数。
如果一个函数作为errback
添加到延迟中,并且延迟已经执行到前一个步骤返回了一个Failure
对象(或者抛出了一个异常,Twisted会将其转换为Failure
对象),那么errback
会被调用,并传入这个Failure
对象。注意!如果errback没有返回一个Failure
,那么延迟会回到调用callback
链,而不是errback!
引用Krondo的第9部分:
虽然这一切看起来有点复杂,但它让你能够在延迟执行过程中实现错误恢复,这非常有用(在协议设计中并不少见)
也就是说:(引用Krondo的第9部分):
总结一下,你认为“我期望这个错误任务返回false”的错误在于finished
并不是由任何错误任务调用的,它是由延迟调用的,而且它只在成功时被调用(因为它只作为callback
加载到延迟中,而不是errback
)
如果你将finished
函数同时作为errback
和callback
加载(可能通过addBoth
),并且你遵循了答案的建议,通过返回Failure
对象来转发errback的返回状态,你的finished
函数技术上仍然不会接收到 False
!它会接收到一个Failure
对象。
……正如我所说,这方面有很多微妙之处……
如果你觉得这些内容有帮助(……即使你觉得没有——我写得不太好),你真的应该去看看Krondo的Twisted入门。我相信在阅读完那个指南后,你会发现很多东西变得清晰明了。