A Twisted Design Decision

Jean-Paul Calderone exarkun at divmod.com
Wed Jan 28 11:40:59 EST 2009


On Wed, 28 Jan 2009 08:05:13 -0800 (PST), koranthala <koranthala at gmail.com> wrote:
>On Jan 28, 8:36 pm, Jean-Paul Calderone <exar... at divmod.com> wrote:
>> [snip]
>> Why isn't the return value of protocol.send propagated back to msg.send?
>> It sounds like it should be.
>>
>> Jean-Paul
>
>Thank you very much again Jean-Paul for helping me out.
>I am unable to understand how I will be able to propogate the return
>value of protocol.send to msg.send.
>Maybe I am being foolish - but my understanding is as follows.
>
>In a non-reactor pattern scenario:
>msg_handler.send_message calls msg.send which inturn calls
>protocol.send.
>So, the reply to protocol.send actually goes up the stack till
>msg_handler.send_message wherein I can increment/decrement success/
>failure counter.
>
>In reactor pattern:
>msg_handler.send_message calls msg.send which call protocol.send which
>causes a deferred to be created.
>Now, when the deferred finishes its work, reactor calls the callback
>associated - but the original context (stack etc) is lost.
>Now, the only mechanism of interaction is via the parameters passed in
>the callback.

You can still interact via return values.  You should be thinking about
a Deferred in the same way as you think about a function which returns
a result synchronously.  The Deferred represents the result, even though
it isn't the result itself (since the result doesn't exist yet).  Anything
you would have done by calling a function and then using its return value
you can do by calling a function and then using the Deferred it returns.

I'll try to update the Twisted version of the code you gave previously to
demonstrate this:


    class MessageHandler:
        def send_message(self):
            def handleResult(result):
                if result:
                   self.success += 1
                else:
                   self.failure += 1 
            if self.execute():
                for i in self.msgs:
                    msg.send().addCallback(handleResult)

    class Message:
        def send(self):
            self.h = h   #The message handler object
            self.update_data() #The data to be sent is updated here
            return self.protocol.send()


    class Protocol:
        @deferredGenerator
        def send(self):
            d = waitForDeferred(getPage(url, method, data))
            yield d
            if page received:
                parse page and see parameters
                if parameters:
                    yield True
                    return
            yield False

See how neither the handler nor the message is passed into the protocol.
The result of the Deferred returned by Protocol.send is instead used by
the handler to do something that the handler knows about.  The encapsulation
is the same as it was in your original example.  The only significant change
is from synchronous return values to Deferred return values.

Jean-Paul



More information about the Python-list mailing list