2011-11-17 18 views
10

Questo è così rotto, spero che tu sia misericordioso con me:Come combinare callLater e addCallback?

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

myFunction restituisce una differita.

spero sia chiaro quello che voglio fare:

  • non appena il reattore è in esecuzione, voglio chiamare myFunction. Questo è il motivo per cui sto usando 0 come parametro di ritardo. Non c'è altro modo tranne callLater? Sembra divertente passare un ritardo di 0.
  • Voglio interrompere il reattore non appena myFunction ha completato l'operazione.

I problemi che ho finora:

  • AttributeError: DelayedCall instance has no attribute 'addCallback'. Giusto! Come posso inserire una richiamata nella catena di callback avviata da myFunction?
  • exceptions.TypeError: stop() takes exactly 1 argument (2 given).

Per risolvere il secondo problema che ho dovuto definire una funzione speciale:

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

e cambiare il codice per:

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

(ancora non funziona a causa del problema callLater, ma stopReactor funzionerà ora)

Non c'è davvero nessun altro modo di chiamare reactor.stop tranne da de multare una funzione extra?

risposta

19

IReactorTime.callLater e Deferred sono mescolati insieme da twisted.internet.task.deferLater.

from twisted.internet import reactor, task 

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

Trovo questa opzione molto leggibile. Il bit 'lambda ignored' mi sembra magico: potresti chiarire cosa fa esattamente? – dangonfast

+4

I callback su un differito vengono chiamati con un argomento. 'reactor.stop' non accetta argomenti. 'lambda ignorato: reactor.stop()' accetta e argomento, lo ignora e chiama 'reactor.stop' senza argomenti. –

+3

Sarebbe un po 'più convenzionale scrivere: "lambda _: reactor.stop" – DonGar

1

Voglio interrompere il reattore non appena myFunction ha completato l'operazione.

Quindi, creare un wrapper che esegue il lavoro di myFunction e quindi arresta il reattore?

0

È necessario associare il callback al differito che myFunction restituisce, poiché callLater non restituisce una funzione. Qualcosa del genere potrebbe funzionare:

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

Ma questo non è testato.

È necessario scrivere una nuova funzione (in questo caso lambda _: reactor.stop()) poiché i richiami a un rinvio eseguono sempre il risultato fino a quel momento.Se vi trovate a voler utilizzare i callback per i loro effetti collaterali e non si preoccupano di moltiplicazione valori spesso, è possibile definire un po 'di funzione di supporto:

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

E poi fare:

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

(Quello che sarebbe davvero bello sarebbe definire un __rshift__ (e analogo sul posto) per la classe Deferred in modo da poter fare: myFunction(parameter1) >> reactor.stop, per quando si vuole abbandonare l'argomento, o myFunction(parameter1) >>= someotherfunc per quando si vuole propagare l'argomento. Se pensi che l'abusiva sintassi haskellish sia "ordinata", comunque.)

0

Se è necessario innescare callback con una certa azione, basta farlo (forse non c'è bisogno di tornare differita, o si dovrebbe occupare). Giusto per chiarire le cose (utilizzando puramente deferreds):

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's our callback to run after triggering `d`  
def d_callback(y): 
    print 'callback ', y 

# now let's 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!'