On 08/26/2010 07:25 PM, Guido van Rossum wrote:

That's not my experience. I wrote a trampoline myself (not released
yet), and found that I had to write a lot more code to deal with the
absence of yield-from than to deal with returns. In my framework,
users write 'raise Return(value)' where Return is a subclass of
StopIteration. The trampoline code that must be written to deal with
StopIteration can be extended trivially to deal with this. The only
reason I chose to use a subclass is so that I can diagnose when the
return value is not used, but I could have chosen to ignore this or
just diagnose whenever the argument to StopIteration is not None.

I'm currently playing around with a trampoline version based on the example in PEP 342. Some of the things I found are ...


* In my version I seperated the trampoline from the scheduler. Having it as a seperate class made the code cleaner and easier to read. A trampoline instance can be ran without the scheduler. (An example of this is below.)

The separate Scheduler only needs a few methods in a coroutine wrapper to run it. It really doesn't matter what's inside it as long as it has a resume method that the scheduler can understand, and it returns in a timely manner so it doesn't starve other coroutines.


* I've found that having a Coroutine class, that has the generator methods on it, is very useful for writing more complex coroutines and generators.


* In a true trampoline, all sub coroutines are yielded out to the trampoline resume loop before their send method is called, so "yield from" isn't needed with a well behaved Trampoline runner.

I think "yield from"'s value is that it emulates a trampolines performance without needing a stack to keep track of caller coroutines. It also saves a lot of looping if you want to write coroutines with sub coroutines without a trampoline runner to run them on.


* Raising StopIteration(value) worked just fine for setting the last value.

Getting the value from the exception just before returning it is still a bit clumsy... I currently use.

     return exc.args[0] if exc.args else None

Maybe I've overlooked something?

My version of the Trampoline class handles the return value since it already has it handy when it gets a StopIteration exception, so the user doesn't need to this, they just need to yield the last value out the same as they do anywhere else.



I wonder if "yield from" may run into pythons stack limit?  For example...

"""
    Factorial Function.
"""
def f(n, k=1):
    if n != 0:
        return f(n-1, k*n)
    else:
        return k

def factoral(n):
    return f(n)

if __name__ == "__main__":
    print(factoral(1000))

This aborts with:
        RuntimeError: maximum recursion depth exceeded in comparison



This one works just fine.

"""
    Factorial Trampoline.
"""
from coroutine.scheduler import Trampoline

def tramp(func):
    def wrap(*args, **kwds):
        t = Trampoline(func(*args, **kwds))
        return t.run()
    return wrap


def f(n, k=1):
    if n != 0:
        yield f(n-1, k*n)
    else:
        yield k

@tramp
def factoral(n):
    yield f(n)

if __name__ == "__main__":
    print(factoral(10000))   # <---- extra zero too!


But if I add another zero, it begins to slow to a crawl as it uses swap space. ;-)

How would a "yield from" version compare?


I'm basically learning this stuff by trying to break this thing, and then trying to fix what breaks as I go. That seems to be working. ;-)

Cheers,
   Ron Adam


_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to