[Python-ideas] Relax __exit__ method to be a generator

Devin Jeanpierre jeanpierreda at gmail.com
Mon Apr 7 03:12:09 CEST 2014


On Sun, Apr 6, 2014 at 6:04 PM, Guido van Rossum <guido at python.org> wrote:
> Well, for new syntax, the bar is pretty high... And we should probably move
> to python-ideas.

And Guido's time machine strikes again! ;)

-- Devin

> On Sun, Apr 6, 2014 at 4:44 PM, Andrew Svetlov <andrew.svetlov at gmail.com>
> wrote:
>>
>> Well, this is good point..
>>
>> But from my experience try/finally is a common point of errors.
>> Beginners use "with" properly as:
>>
>> with open(filename) as f:
>>   f.read()
>>
>> but switch to try/finally produces very common error.
>>
>> Instead of
>>
>> f = open(filename)
>> try:
>>   f.read()
>> finally:
>>   f.close()
>>
>> people usually write
>>
>> try:
>>  f = open(filename)
>>  f.read()
>> finally:
>>   f.close()
>>
>> I saw it constantly many times. When I wrote an article about the
>> problem and true solution in my blog I got several emails from my
>> readers: please, tell me again why I need to move open() out of try
>> block if it can generate exception on file opening?
>>
>> So maybe you would like some other syntax? For example
>>
>> with from obj:
>>    BLOCK
>>
>> That form can use magic methods with names different than
>> __enter__/__exit__ (and get rid of "with (yield from lock)" BTW). And
>> it's obviously? points on two suspending points: at BLOCK enter and
>> exit.
>>
>> On Mon, Apr 7, 2014 at 2:12 AM, Guido van Rossum <guido at python.org> wrote:
>> > I prefer to use a try/finally statement. One of the points of using
>> > yield-from is that you can always tell where your code may be suspended
>> > by
>> > searching for "yield from". With your proposed change that would no
>> > longer
>> > be true -- any with statement would also have to be inspected, and there
>> > would no longer be a way to know from the source alone whether it might
>> > yield or not (because it would dynamic -- there's no way to be sure at
>> > compile time which context manager is being used).
>> >
>> >
>> > On Sun, Apr 6, 2014 at 12:02 PM, Andrew Svetlov
>> > <andrew.svetlov at gmail.com>
>> > wrote:
>> >>
>> >> Literally it may be generator itself or function that returns generator
>> >> object.
>> >>
>> >> Now I'm working on postgres library for asyncio
>> >> (http://aiopg.readthedocs.org/).
>> >>
>> >> And I would to use *with statement* for transaction handling like:
>> >>
>> >> with (yield from cursor.transaction()):
>> >>    yield from cursor.execute(sql)
>> >>
>> >> The problem is: at exit of *with statement* I need to call `yield from
>> >> cursor.execute('COMMIT')` or `yield from cursor.execute('ROLLBACK')`.
>> >>
>> >> I can do it only in __exit__ in *context manager*, but python
>> >> understand only if __exit__:
>> >> - returns true value, that suppresses exception from code block
>> >> - returns None or any false value to propagate exception if any
>> >> - raises exception itself
>> >>
>> >> I propose to add new rule:
>> >> IF the code object is generator (co_flags & CO_GENERATOR) and __exit__
>> >> returns generator object (isinstance(ret, types.GeneratorType))
>> >> THEN do `yield from ret`.
>> >>
>> >> That's work fine if __exit__ itself is a *generator function*
>> >> (contains `yield` or `yield from` statements): call to *generator
>> >> function* returns *generator object*.
>> >>
>> >> The proposal:
>> >> 1. Doesn't break any existing code except if user accidentally
>> >> returns generator object instead of True from __exit__ call (he should
>> >> not to do this and I sure this is very rare case).
>> >> 2. Don't requires new syntax.
>> >>
>> >> asyncio itself uses:
>> >>
>> >> with (yield from lock):
>> >>    BLOCK
>> >>
>> >> for locking etc but unlocking for asyncio objects doesn't requires any
>> >> `yield from`, so __exit__ code is just plain function but not
>> >> generator.
>> >>
>> >> Also I can live with asyncio trick for __enter__:
>> >> https://code.google.com/p/tulip/source/browse/asyncio/locks.py#156
>> >> The way is a but annoying but unrolling a value returned by __enter__
>> >> if the value is generator object will break existing code, sure.
>> >>
>> >> Thoughts?
>> >>
>> >>
>> >> --
>> >> Thanks,
>> >> Andrew Svetlov
>> >> _______________________________________________
>> >> Python-ideas mailing list
>> >> Python-ideas at python.org
>> >> https://mail.python.org/mailman/listinfo/python-ideas
>> >> Code of Conduct: http://python.org/psf/codeofconduct/
>> >
>> >
>> >
>> >
>> > --
>> > --Guido van Rossum (python.org/~guido)
>>
>>
>>
>> --
>> Thanks,
>> Andrew Svetlov
>
>
>
>
> --
> --Guido van Rossum (python.org/~guido)
>
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/


More information about the Python-ideas mailing list