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
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4