Hi,
I was following asynchronous discussions in python mailing list and stumbled upon Guido idea of callback handling: raise StopIteration if you want to return something. It is pretty neat idea and not sure why I haven't thought of it before :-)
As an example, if you use gen.engine now, your function might look like this:
@gen.engine
def handle(param1, param2, callback):
if param1 == '1':
callback(param1)
elif param2 == '2':
callback(param2)
else:
callback(None)
As Ben mentioned, with current approach, you have to fall through the method after you called callback function to prevent rest of the function from the execution.
This won't work as expected:
@gen.engine
def handle(param1, param2, callback):
if param1 == '1':
callback(param1)
if param2 == '2':
callback(param2)
else:
callback(None)
Instead, you can write something like this, which does not look very pretty
@gen.engine
def handle(param1, param2, callback):
if param1 == '1':
callback(param1)
raise StopIteration()
if param2 == '2':
callback(param2)
else:
callback(None)
Luckily enough, you can stop iterator by raising StopIteration exception and you can use exception instance to pass values back from generator.
For example, previous function can be modified to look like this:
@gen.async
def handle(param1, param2):
if param1 == '1':
gen.ret(param1)
if param2 == '2':
gen.ret(param2)
Comments:
1. gen.async is just modified version of gen.engine with custom runner;
2. gen.ret will raise StopIteration() with return value(s);
3. Callback won't be exposed to the function and will be called by the runner. No need to keep queue of "not called" callbacks for safety reasons - there's guarantee that callback will be called;
4. Default return value is None, same as in normal Python functions. If caller does not expect None, that's their problem;
5. Only problem that I see - if you have exception handler in the function, you have to care about StopIteration exceptions:
@gen.async
def handle(param1, param2):
try:
if param1 == '1':
gen.ret(param1)
if param2 == '2':
gen.ret(param2)
except StopIteration:
raise
except Exception:
# Do something
pass
I can make gist to illustrate approach along with few examples.
Any thoughts or comments?
Serge.