Using python coroutines to implement easy of use state machines
Michael 'Mickey' Lauer
mickey at vanille-media.de
Mon May 26 22:14:42 CEST 2008
Hi,
On Monday 26 May 2008 05:24:28 Guillaume Chereau wrote:
> I am having a look at the python-ophoned code, and I see that it relies
> a lot on call back functions to implement some sort of state machines.
> (I am not really sure of the real mathematical term I should use)
>
> Something like this :
>
> def process():
> print "start process"
> # start an asynchronous function
> call_asynchronous(an_other_process, call_back = process_next)
>
> def process_next(value)
> print "an_other_process returned", value
>
>
> Well, there is a python trick that is getting popular now that can ease
> a lot the implementation of such functions. The idea is to use the yield
> keyword to write coroutines (functions that can be exited and restarted
> at any internal point).
>
> The previous example could be written like this :
>
> def process():
> print "start process"
> value = ( yield call_asynchronous(an_other_process) )
> print "an_other_process returned", value
>
Yeah, I'm familiar with that. To be honest, I already tried doing something
like that (but it didn't work in 30 minutes and then I gave up ;) since I was
kind of fed up with all these callbacks. There's two interesting usecases
here, one with the client and one with the server. In fact, I think it's even
more important to have that client-side than server-side.
But lets first talk about server. Basically what I'd love to have is instead
of:
#=========================================================================#
class DeviceSetAntennaPower( DeviceMediator ):
#=========================================================================#
def trigger( self ):
self._commchannel.enqueue( "+CFUN?", self.intermediateResponse,
self.errorFromChannel )
def intermediateResponse( self, request, response ):
assert response[-1] == "OK"
state = self._rightHandSide( response[0] ) == "1"
if state == self.power:
# nothing to do
self._ok()
else:
self._commchannel.enqueue( "+CFUN=%d" % self.power,
self.responseFromChannel, self.errorFromChannel )
@logged
def responseFromChannel( self, request, response ):
if response[-1] == "OK":
self._ok()
else:
DeviceMediator.responseFromChannel( self, request, response )
rather something like this:
#=========================================================================#
class DeviceSetAntennaPower( DeviceMediator ):
#=========================================================================#
def trigger( self ):
( response, error ) = yield( "+CFUN?" )
if error is not None:
self.errorFromChannel( error )
assert response[-1] == "OK"
state = self._rightHandSide( response[0] ) == "1"
if state == self.power:
# nothing to do
self._ok()
else:
( response, error ) = yield( "+CFUN=%d" % self.power )
if response[-1] == "OK":
self._ok()
else:
DeviceMediator.responseFromChannel( self, request, response )
This would be really nice, more understandable, and more maintainable.
> So my question is : Shouldn't we use this as well ? It is the current
> trend in python programs, and it makes the code much much simpler.
I'm not particular liking the gtasklets (now: kiwi tasklets) implementation,
but I think you should spend some days trying to see whether you can make the
aforementioned happen.
> The
> only problem is that many people are not familiar with coroutine, since
> it doesn't exist in C, and they are not used to write software that rely
> on this.
That should be no problem. People will love that. Like i said, especially on
the client we see that problem as well. Almost all org.freesmartphone.GSM
calls should be called asynchronously, since they could block for seconds (or
minutes, hey, it's a MODEM -- 1990s technology). So, if you could also come
up for something that makes the dbus calls on the client using result = yield
(call), I'd be even more happy.
:M:
--
Dr. Michael 'Mickey' Lauer | IT-Freelancer | http://www.vanille-media.de
More information about the smartphones-standards
mailing list