[Python-ideas] PEP 380 close and contextmanagers?
rrr at ronadam.com
Thu Oct 28 02:00:52 CEST 2010
On 10/27/2010 01:38 PM, Guido van Rossum wrote:
> 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?
I think that was what I was trying to figure out also.
>> def reduce_i(f):
>> i = yield
>> while True:
>> i = f(i, (yield i))
> Unfortunately from here on till the end of your example my brain exploded.
Mine did too, but I think it was a useful but strange experience. ;-)
It forced me to take a break and think about the problem from a different
viewpoint. Heres the conclusion I came to, but be forewarned, it's kind of
The use of an exception to signal some bit of code, is a way to reach over
a wall that also protects that bit of code. This seems to be a more common
need when using coroutines, because it's more common to have some bits of
code indirectly, direct some other bit of code.
Generators already have a nice .throw() method that will return the value
at the next yield. But we either have to choose an existing exception to
throw, that has some other purpose, or make up a new one. When it comes to
making up new ones, lots of other programmers may each call it something else.
That isn't a big problem, but it may be nice if we had a standard exception
for saying.. "Hey you!, send me a total or subtotal!". And that's all that
it does. For now lets call it a ValueRequest exception.
ValueRequest makes sense if you are throwing an exception, I think
ValueReturn may make more sense if you are raising an exception. Or maybe
there is something that reads well both ways? These both fit very nice
with ValueError and it may make reading code easier if we make a
distinction between a request and a return.
Below is the previous example rewritten to do this. A ValueRequest doesn't
stop anything or force anything to close, so it wont ever interfere,
confuse, or complicate, code that uses other exceptions. You can always
throw or catch one of these and raise something else if you need to.
Since throwing it into a generator doesn't stop the generator, the
generator can put the try-except into a larger loop and loop back to get
more values and catch another ValueRequest at some later point. I feel
that is a useful and handy thing to do.
So here's the example again.
The first version of this took advantage of yield's ability to send and get
data at the same time to always send back an update (subtotal) to the
parent routine. That's nearly free since a yield always sends something
back anyway. (None if you don't give it something else.) But it's not
always easy to do, or easy to understand if you do it. IE.. brain
In this version, data only flows into the coroutine until a ValueRequest
exception is thrown at it, at which point it then yields back a total.
*I can see where some routines may reverse the control, by throwing
ValueReturns from the inside out, rather than ValueRequests from the
outside in. Is it useful to distinquish between the two or should there
be just one?
*Yes this can be made to work with gclose() and return, but I feel that is
more restrictive, and more complex, than it needs to be.
*I still didn't figure out how to use the context managers to get rid of
the try except. Oh well. ;-)
from contextlib import contextmanager
def consumer(cofunc, result=True):
def multiconsumer(cofuncs, result=True):
for c in cofuncs:
for c in cofuncs:
# 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.
x = yield
x = f(x, (yield))
with multiconsumer([reduce_item(f) for f in funcs]) as mc:
x = yield
for c in mc:
yield [c.throw(ValueRequest) for c in mc]
def get_reductions(funcs, iterable):
with consumer(reduce_group(funcs)) as c:
for x in iterable:
funcs = [min, max]
s = "Python is fun for play, and great for work too."
if __name__ == '__main__':
More information about the Python-ideas