[Twisted-Python] generating and handling events
Bob Ippolito
bob at redivi.com
Thu May 26 02:00:30 MDT 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