[Python-ideas] Possible PEP 380 tweak (original) (raw)
Ron Adam rrr at ronadam.com
Sat Oct 30 08:42:18 CEST 2010
- Previous message: [Python-ideas] Possible PEP 380 tweak
- Next message: [Python-ideas] Possible PEP 380 tweak
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
On 10/29/2010 10:09 PM, Greg Ewing wrote:
Guido van Rossum wrote:
This seems to be the crux of your objection. But if I look carefully at the expansion in the current version of PEP 380, I don't think this problem actually happens: If the outer generator catches GeneratorExit, it closes the inner generator (by calling its close method, if it exists) and then re-raises the GeneratorExit: Yes, but if you want close() to cause the generator to finish normally, you don't want that to happen. You would have to surround the yield-from call with a try block to catch the GeneratorExit, and even then you would lose the return value from the inner generator, which you're probably going to want.
Ok, after thinking about this for a while, I think the "yield from" would be too limited if it could only be used for consumers that must run until the end. That rules out a whole lot of pipes, filters and other things that consume-some, emit-some, consume-some_more, and emit-some_more.
I think I figured out something that may be more flexible and insn't too complicated.
The trick is how to tell the "yield from" to stop delegating on a particular exception. (And be explicit about it!)
# Inside a generator or sub-generator.
...
next(<my_gen>) # works in this frame.
yield from <my_gen> except <exception> #Delegate until <exception>
value = next(<my_gen>) # works in this frame again.
...
The explicit "yield from .. except" is easier to understand. It also avoids the close and return issues. It should be easier to implement as well. And it doesn't require any "special" framework in the parent generator or the delegated sub-generator to work.
Here's an example.
I prefer to use a ValueRequest exception, but someone could use
StopIteration or GeneratorExit, if it's useful for what they
are doing.
class ValueRequest(Exception): pass
A pretty standard generator that emits
a total when an exception is thrown in.
It doesn't need anything special in it
so it can be delegated.
def gtally(): count = tally = 0 try: while 1: tally += yield count += 1 except ValueRequest: yield count, tally
An example of delegating until an Exception.
The specified "exception" is not sent to the sub-generator.
I think explicit is better than implicit here.
def gtally_averages(): gt = gtally() next(gt) yield from gt except ValueRequest #Catches exception count, tally = gt.throw(ValueRequest) #Get tally yield tally / count
This part also already works and has no new stuf in it.
This part isn't aware of any delegating!
def main(): gavg = gtally_averages() next(gavg) for x in range(100): gavg.send(x) print(gavg.throw(ValueRequest))
main()
It may be that a lot of pre-existing generators will already work with this. ;-)
You can still use 'yield from " to delegate until ends. You just won't get a value in the same frame was used in. The parent may get it instead. That may be useful in it self.
Note: you can't put the yield from inside a try-except and do the same thing. The exception would go to the sub-generator instead. Which is one of the messy things we are trying to avoid doing.
Cheers, Ron
- Previous message: [Python-ideas] Possible PEP 380 tweak
- Next message: [Python-ideas] Possible PEP 380 tweak
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]