twisted中Deferred对象callback返回值为Deferred对象时

《Learning Scrapy》第225页看到这一段:

>>> # Experiment 3
>>> def status(*ds):
... return [(getattr(d, 'result', "N/A"), len(d.callbacks)) for d in
ds]
>>> def b_callback(arg):
... print "b_callback called with arg =", arg
... return b
>>> def on_done(arg):
... print "on_done called with arg =", arg
... return arg
>>> # Experiment 3.a
>>> a = defer.Deferred()
>>> b = defer.Deferred()
>>> a.addCallback(b_callback).addCallback(on_done)
>>> status(a, b)
[('N/A', 2), ('N/A', 0)]
>>> a.callback(3)
b_callback called with arg = 3
>>> status(a, b)
[(<Deferred at 0x10e7209e0>, 1), ('N/A', 1)]
>>> b.callback(4)
on_done called with arg = 4
>>> status(a, b)
[(4, 0), (None, 0)]

对于种结果百思不得其解,最后从源码注释中找到了答案:

line 444:
If a callback (or errback) returns another L{Deferred}, this L{Deferred} will be chained to it (and further callbacks will not run until that L{Deferred} has a result).

执行过程从第668行开始:

    if isinstance(current.result, Deferred):
        # The result is another Deferred.  If it has a result,
        # we can take it and keep going.
        resultResult = getattr(current.result, 'result', _NO_RESULT)
        if resultResult is _NO_RESULT or isinstance(resultResult, Deferred) or current.result.paused:
            # Nope, it didn't.  Pause and chain.
            current.pause()
            current._chainedTo = current.result
            # Note: current.result has no result, so it's not
            # running its callbacks right now.  Therefore we can
            # append to the callbacks list directly instead of
            # using addCallbacks.
            current.result.callbacks.append(current._continuation())
            break

这就解释了为何运行到b.callback(4)时,a的状态包含“waiting for Deferred”。此时a处于pause状态。

那么后续的这一段也能理解了:

>>> # Experiment 3.b
>>> a = defer.Deferred()
>>> b = defer.Deferred()
>>> a.addCallback(b_callback).addCallback(on_done)
>>> status(a, b)
[('N/A', 2), ('N/A', 0)]
>>> b.callback(4)
>>> status(a, b)
[('N/A', 2), (4, 0)]
>>> a.callback(3)
b_callback called with arg = 3
on_done called with arg = 4
>>> status(a, b)
[(4, 0), (None, 0)]

执行callback后,依次调用_startRunCallbacks_runCallbacks方法。在_startRunCallbacks中,self.result先被赋值为4,而在_runCallbacks中,“while current.callbacks:”包裹的循环会进一步影响self.result的值。
所以callback chain为[]时,也能调用callback并产生result。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值