Как объединить callLater и addCallback?
Это так сломано, надеюсь, вы со мной милостивы:
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
за исключением определения дополнительной функции?
Ответы
Ответ 1
IReactorTime.callLater
и Deferred
смешиваются вместе twisted.internet.task.deferLater
.
from twisted.internet import reactor, task
d = task.deferLater(reactor, 0, myFunction, parameter1)
d.addCallback(lambda _: reactor.stop())
reactor.run()
Ответ 2
Я хочу остановить реактор, как только myFunction выполнит задачу.
Итак, создайте обертку, которая работает myFunction, а затем остановит реактор?
def wrapper(reactor, *args):
myFunction(*args)
reactor.stop()
reactor.callLater(0, wrapper, reactor, ...)
Ответ 3
Вам нужно приложить обратный вызов к отложенному, который возвращает myFunction, поскольку callLater не возвращает функцию. Возможно, что-то подобное:
reactor.callLater(0, lambda: myFunction(parameter1).addCallback(lambda _: reactor.stop())
Но это не проверено.
Вам нужно написать новую функцию (здесь лямбда _: reactor.stop()), потому что обратные вызовы к отложенному всегда принимают результат до этого. Если вы обнаружите, что хотите использовать обратные вызовы для своих побочных эффектов, и вы часто не заботитесь о распространении значений, вы можете определить небольшую вспомогательную функцию:
def ignoringarg(f):
return lambda _: f()
И затем выполните:
reactor.callLater(0, lambda: myFunction(paramater1).addCallback(ignoringarg(reactor.stop)))
(То, что было бы действительно аккуратно, было бы определить __rshift__
(и локальный аналог) для класса Deferred
, чтобы вы могли сделать: myFunction(parameter1) >> reactor.stop
, когда вы хотите отказаться от аргумента или myFunction(parameter1) >>= someotherfunc
, если вы хотите распространять аргумент. Если вы считаете, что злоупотребление синтаксисом haskellish является "опрятным", во всяком случае.)
Ответ 4
Если вам нужно активировать обратный вызов с каким-либо действием, просто сделайте это (возможно, нет необходимости возвращать отложенную или smth).
Просто, чтобы прояснить ситуацию (используя чисто отложенные):
from twisted.internet import reactor, defer
# That will be our deferred to play with
# it has callback and errback methods
d = defer.Deferred()
def my_function(x):
print 'function', x
# need to trigger deferred upon function run?
# Lets tell it to do so:
d.callback(x)
# That our callback to run after triggering `d`
def d_callback(y):
print 'callback ', y
# now let bind that callback to be actually launched by `d`
d.addCallback(d_callback)
# now adding another callback just to stop reactor
# note lambda simply helps to agree number of arguments
d.addCallback(lambda data: reactor.stop())
# so we'll call `my_function` in 2 secs, then it runs
# then it triggers `d` to fire its callbacks
# then `d` actually detonates the whole chain of its added callbacks
reactor.callLater(2, my_function, 'asdf') # 'asdf' is some stupid param
# Here how it works
print 'Lets start!'
reactor.run()
print 'Done!'