Using python coroutines to implement easy of use state machines

Michael 'Mickey' Lauer mickey at vanille-media.de
Tue Jun 3 13:41:26 CEST 2008


On Wednesday 28 May 2008 08:42:22 Guillaume Chereau wrote:
> On Tue, 2008-05-27 at 14:41 +0800, Guillaume Chereau wrote:
> > Aah, I just finished doing a simple "proof of concept" library to show
> > how it could work (server side). I am quite happy with it because it
> > allows generators OR callbacks syntax (in fact the library just provides
> > a wrapper to a callback mechanism), so it is very easy to use with the
> > gobject callback functions.

Awesome, thanks a lot. I think this will be very handy in a lot of places, 
especially client side. I solved it a bit differently in the ophoned server 
though, because a) we don't need traceback exception handling here (since 
exceptions come in other form), and I adore the simplicity and elegance of 
the <result> = yield <request> form.

For reference, this is what I came up with:

#=========================================================================#
class AbstractYieldSupport( object ):
#=========================================================================#
    """
    This class adds support for simplifying control flow
    by using Python generators to implement coroutines.
    By inheriting from this class, you can use the following syntax:

    def trigger( self ):
        for iteration in ( 1,2,3,4 ):
            request, response, error = yield( "+CFUN=1" )
            if error is None:
                self._ok( response )
            else:
                self.errorFromChannel( request, error )
    """

    def __init__( self, *args, **kwargs ):
        self.generator = self.trigger()
        if self.generator is not None:
            toEnqueue = self.generator.next()
            self._commchannel.enqueue( toEnqueue, self.genResponseFromChannel, 
self.genErrorFromChannel )

    def trigger( self ):
        assert False, "pure virtual method called"

    @logged
    def genResponseFromChannel( self, request, response ):
        try:
            toEnqueue = self.generator.send( ( request, response, None ) )
        except StopIteration:
            pass
        else:
            self._commchannel.enqueue( toEnqueue, self.genResponseFromChannel, 
self.genErrorFromChannel )

    @logged
    def genErrorFromChannel( self, request, error ):
        try:
            toEnqueue = self.generator.send( ( request, None, error ) )
        except StopIteration:
            pass
        else:
            self._commchannel.enqueue( toEnqueue, self.genResponseFromChannel, 
self.genErrorFromChannel )


:M:
-- 
Dr. Michael 'Mickey' Lauer | IT-Freelancer | http://www.vanille-media.de



More information about the smartphones-standards mailing list