如何结合callLater和addCallback?

11 投票
4 回答
10834 浏览
提问于 2025-04-17 06:31

这真是太糟糕了,希望你能对我宽容一些:

reactor.callLater(0, myFunction, parameter1).addCallback(reactor.stop)
reactor.run()

myFunction 返回一个延迟对象。

我希望我想做的事情能让你明白:

  • 一旦反应器开始运行,我想立刻调用 myFunction。所以我把延迟参数设置为0。除了用callLater,还有其他方法吗?把延迟设置为0听起来有点奇怪。
  • 我想在 myFunction 完成任务后立刻停止反应器。

到目前为止我遇到的问题:

  • AttributeError: DelayedCall instance has no attribute 'addCallback'。这很合理!那我该怎么把回调放到 myFunction 开始的回调链里呢?
  • exceptions.TypeError: stop() takes exactly 1 argument (2 given)

为了解决第二个问题,我不得不定义一个特殊的函数:

def stopReactor(result):
    gd.log.info( 'Result: %s' % result)
    gd.log.info( 'Stopping reactor immediatelly' )
    reactor.stop()

然后把代码改成:

reactor.callLater(0, myFunction, parameter1).addCallback(stopReactor)
reactor.run()

(因为callLater的问题,还是不工作,但 stopReactor 现在可以用了)

真的没有其他方法可以调用 reactor.stop 吗?非得定义一个额外的函数不可?

4 个回答

0

你需要把回调函数绑定到myFunction返回的那个延迟对象上,因为callLater并不会返回一个函数。像这样可能会有效:

reactor.callLater(0, lambda: myFunction(parameter1).addCallback(lambda _: reactor.stop())

不过这个还没有经过测试。

你需要写一个新的函数(这里是lambda _: reactor.stop()),因为对延迟对象的回调总是会使用到之前的结果。如果你发现自己想用回调函数来处理一些副作用,而不太关心传递值的情况,你可以定义一个小助手函数:

def ignoringarg(f):
    return lambda _: f()

然后可以这样做:

reactor.callLater(0, lambda: myFunction(paramater1).addCallback(ignoringarg(reactor.stop)))

(如果能为Deferred类定义一个__rshift__(以及一个就地的类似功能),那就太好了,这样你就可以这样写:myFunction(parameter1) >> reactor.stop,当你想放弃参数时,或者myFunction(parameter1) >>= someotherfunc,当你想传递参数时。如果你觉得这种“滥用”haskell风格的语法是“不错”的话。)

1

我想在myFunction完成任务后立刻停止反应器。

那么,创建一个包装器,先执行myFunction的工作,然后再停止反应器吗?

def wrapper(reactor, *args):
    myFunction(*args)
    reactor.stop()

reactor.callLater(0, wrapper, reactor, ...)
24

IReactorTime.callLaterDeferred 是通过 twisted.internet.task.deferLater 混合在一起的。

from twisted.internet import reactor, task

d = task.deferLater(reactor, 0, myFunction, parameter1)
d.addCallback(lambda ignored: reactor.stop())
reactor.run()

撰写回答