[Python-ideas] PEP 380 close and contextmanagers? (original) (raw)
Guido van Rossum guido at python.org
Wed Oct 27 20:38:49 CEST 2010
- Previous message: [Python-ideas] PEP 380 close and contextmanagers?
- Next message: [Python-ideas] PEP 380 close and contextmanagers?
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
On Wed, Oct 27, 2010 at 9:18 AM, Ron Adam <rrr at ronadam.com> wrote:
On 10/27/2010 10:01 AM, Ron Adam wrote: It looks like No context managers return values in the finally or exit part of a context manager. Is there way to do that?
How would that value be communicated to the code containing the with-clause?
Here's a context manager version of the min/max with nested coroutines, but it doesn't return a value from close.
###### from contextlib import contextmanager # New close function that enables returning a # value. def gclose(gen): try: gen.throw(GeneratorExit) except StopIteration as err: if err.args: return err.args[0] except GeneratorExit: pass return None # Showing both the class and geneator based # context managers for comparison and to better # see how these things may work. class Consumer: def init(self, cofunc): next(cofunc) self.cofunc = cofunc def enter(self): return self.cofunc def exit(self, *excinfo): gclose(self.cofunc) @contextmanager def consumer(cofunc): next(cofunc) try: yield cofunc finally: gclose(cofunc) class MultiConsumer: def init(self, cofuncs): for c in cofuncs: next(c) self.cofuncs = cofuncs def enter(self): return self.cofuncs def exit(self, *excinfo): for c in self.cofuncs: gclose(c) @contextmanager def multiconsumer(cofuncs): for c in cofuncs: next(c) try: yield cofuncs finally: for c in cofuncs: gclose(c)
So far so good.
# Min/max coroutine example slpit into # nested coroutines for testing these ideas # in a more complex situation that may arise # when working with cofunctions and generators.
# Question: # How to rewrite this so close returns # a final value?
Change the function to catch GeneratorExit and when it catches that, raise StopIteration().
def reducei(f): i = yield while True: i = f(i, (yield i))
Unfortunately from here on till the end of your example my brain exploded.
def reduceitto(funcs): with multiconsumer([reducei(f) for f in funcs]) as mc: values = None while True: i = yield values values = [c.send(i) for c in mc]
Maybe you could have picked a better name than 'i' for this variable...
def main(): with consumer(reduceitto([min, max])) as c: for i in range(100): value = c.send(i) print(value)
I sort of get what you are doing here but I think you left one abstraction out. Something like this:
def blah(it, funcs): with consumer(reduce_it_to(funcs) as c: for i in it: value = c.send(i) return value
def main(): print(blah(range(100), [min, max]))
if name == 'main': main()
-- --Guido van Rossum (python.org/~guido)
- Previous message: [Python-ideas] PEP 380 close and contextmanagers?
- Next message: [Python-ideas] PEP 380 close and contextmanagers?
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]