Python DeferredList 回调成功但 deferreds 报错

0 投票
2 回答
2007 浏览
提问于 2025-04-18 04:39

我有一个简单的脚本:

#!/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 个回答

3

如果你没有从你的 errback 函数中返回错误或异常,那么这个错误就会被认为是已经处理过了。试着修改你的 error() 函数:

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

这样一来,错误(results)就会被返回,然后 DeferredList 会看到这个错误,并且也会调用它的 errback 函数。

4

让我补充一点你没有选择的想法:

在你的问题中,你打印了一个参数,这个参数是你的延迟(callback)函数(finished)被调用时的值,而你注意到你期望它是false(因为之前发生了错误)

这种期望表明你对延迟的理解可能会让你在后面感到困惑

让我试着把这个拆开来讲讲……

(这方面有很多细节和微妙之处,我会尽量解释清楚)

延迟是:

  1. 一个函数回调的队列
  2. 对于队列中的每一个“步骤”,都有一个callback和一个errback函数回调被存储
    • addCallbacks(注意是复数)可以让你同时添加callback和errback
    • addCallback添加一个callback(并将errback设置为跳过队列中的下一个条目)
    • addErrback添加一个errback(并将callback设置为跳过队列中的下一个条目)
    • addBoth将一个函数同时作为errback和callback添加(这意味着它需要通过传入的参数来判断自己为什么被调用)

引用Krondo的第7部分:(……Twisted文档也有很好的图示

Krondo的延迟图示

如果一个函数作为callback添加到延迟中,并且延迟已经执行到前一个步骤成功返回的那一刻,延迟会将前一个成功函数的返回值传递给callback中定义的函数。

如果一个函数作为errback添加到延迟中,并且延迟已经执行到前一个步骤返回了一个Failure对象(或者抛出了一个异常,Twisted会将其转换为Failure对象),那么errback会被调用,并传入这个Failure对象。注意!如果errback没有返回一个Failure,那么延迟会回到调用callback链,而不是errback!

引用Krondo的第9部分

callback和errback之间的连接

虽然这一切看起来有点复杂,但它让你能够在延迟执行过程中实现错误恢复,这非常有用(在协议设计中并不少见)

也就是说:(引用Krondo的第9部分):

krondo的延迟从错误中恢复的图示

总结一下,你认为“我期望这个错误任务返回false”的错误在于finished并不是由任何错误任务调用的,它是由延迟调用的,而且它只在成功时被调用(因为它只作为callback加载到延迟中,而不是errback

如果你将finished函数同时作为errbackcallback加载(可能通过addBoth),并且你遵循了答案的建议,通过返回Failure对象来转发errback的返回状态,你的finished函数技术上仍然不会接收到 False!它会接收到一个Failure对象。

……正如我所说,这方面有很多微妙之处……

如果你觉得这些内容有帮助(……即使你觉得没有——我写得不太好),你真的应该去看看Krondo的Twisted入门。我相信在阅读完那个指南后,你会发现很多东西变得清晰明了。

撰写回答