[Twisted-Python] generating and handling events

Bob Ippolito bob at redivi.com
Thu May 26 04:00:30 EDT 2005


On May 25, 2005, at 11:37 PM, theshz wrote:

> Hi, from the documentation I could only find examples where the  
> events are
> related more to Deferred, i.e., a method call that may take  
> sometime. I'm a
> little confused about the difference between this and the  
> "traditional" kind
> of event handling. Are they the same with just different  
> terminology? By
> "traditional", I mean that in part of the code, I generate an  
> event, say a
> "step 1 finished event", somewhere else there is a handler waiting  
> for this
> event. The reactor is responsible for dispatching this event to that
> handler, which hopefull starts step 2. Or even more, like publish- 
> subscribe:
> multiple handers can register for the same event. In other words,  
> these
> events are generated internally, not necessarily by such delays like
> network, file access, or user input. Is this doable in Twisted?

Deferreds are just objects that have a list of (result, error)  
callback pairs.  When the result or error is available, it's passed  
to the first appropriate callback.  The result or error returned by  
that callback is sent to the next, etc.  Its job is to pass that  
*single* result on to everything in its callback chain either one or  
zero times, and then it should be garbage collected because its job  
is done.

The way this would works is like this (bare bones example without any  
error handling, etc.):

###

from twisted.internet import defer, reactor

def step1():
     d = defer.Deferred()
     # In two seconds, call the callback with the result 42
     reactor.callLater(2.0, d.callback, 7)
     return d

def step2(resultOfStep1):
     d = defer.Deferred()
     # In two seconds, call the callback with the result of the
     # argument times 6
     reactor.callLater(2.0, d.callback, resultOfStep1 * 6)
     return d

def doAllSteps():
     # step1 returns a deferred
     d = step1()
     # step 2 takes the result of step1 as an argument
     # so we can use it as the callback for the deferred,
     # since the callback always receives the result as the
     # first argument
     d = d.addCallback(step2)
     # the other thing to note is that step2 returns a deferred, which
     # will automatically be chained, so we can just return it here
     # as our deferred
     return d

def main():
     def printResultAndQuit(result):
         print "the answer is:", result
         reactor.stop()

     d = doAllSteps()
     d.addCallback(printResultAndQuit)

     # this should think for about 4 seconds,
     # print the answer to everything, and then
     # return.
     reactor.run()

if __name__ == '__main__':
     main()

###

It is an excellent primitive for building a notification system on  
top of, but it isn't one.  As you can see in Twisted's source, there  
is rarely a need for an event dispatching system, so one doesn't  
really exist (there is one on the reactor for startup and shutdown  
events, but that's about it).  In almost all cases the "problem" is  
solved by:
(a) having some particular name for a method to be implemented in a  
subclass (e.g. subclass LineReceiver and implement lineReceived)
(b) using a delegate that implements some method with a particular  
name (e.g. protocols telling their transport to lose connection, or  
transports notifying their protocol of a lost connection)
(c) using deferreds (i.e. twisted.web.server.Request.notifyFinish)

The only one that looks like traditional publish-subscribe is really  
the reactor's system events (twisted.internet.interfaces.IReactorCore)

-bob





More information about the Twisted-Python mailing list