
On Mon, Mar 16, 2009 at 11:26 AM, Steven Bethard <steven.bethard@gmail.com> wrote:
On Mon, Mar 16, 2009 at 11:06 AM, Guido van Rossum <guido@python.org> wrote:
Moreover, since the main use case seems to be fixing a corner case of the nested() context manager, perhaps the effort towards changing the language would be better directed towards supporting "with a, b:" as a shorthand for "with a: with b:" .
On Mon, Mar 16, 2009 at 10:01 AM, Guido van Rossum <guido@python.org> wrote:
I have no right to speak because I haven't read through all the details of the proposal, but reading this I am very sad that we have to introduce a whole new exception (and one with special status as well) in order to fix such a niggly corner case of the context manager protocol.
Since IIUC the original context manager design was intended to have exactly one yield in the body of the context manager -- can't we just declare fewer (or more) yields an error and rase an appropriate TypeError or something?
It's not really a generator specific thing. You can generate similar problems by just defining a class with an __enter__() method that raises an exception.
Huh? According to PEP 343, if __enter__ raises an exception, that's the end of the story. __exit__ shouldn't be called, the exception is not modified, the flow is interrupted right there.
But I agree that it seems like a big change for a small corner case. Is there anything other than contextlib.nested() which needs this? If there is no other use case, then I'm a strong +1 for Guido's suggestion of providing syntactic support for ``with a, b:`` instead.
BTW, I think the explanation of the problem isn't as clear as it could be. The core problem, if I understand it right, is that contextlib.nested() is not equivalent to a real nested with statement because it calls the nested __enter__() methods too early. A real nested with statement translates into something like::
mgr1.__enter__() try: mgr2.__enter__() try: BLOCK except: ... except: if not mgr1.__exit__(*sys.exc_info()): raise
But contextlib.nested() calls all the __enter__() methods in its own __enter__() so it translates into something like::
mgr1.__enter__() mgr2.__enter__() try: BLOCK except: ...
The key problem here is that ``mgr2.__enter__()`` is outside of the try block, and the context manager has no way to put it inside. So the thing that contextlib.nested() really needs is a way to be able to insert statements into the BLOCK part of the code. (I'm not actually suggesting we go this route, but that seems to be what contextlib.nested() is really after.)
Yeah, it really seems pretty much limited to contextlib.nested(). I'd be happy to sacrifice the possibility to *exactly* emulate two nested with-statements. The cost of a new exception is huge -- everyone will have to explain its existence, and historically "you don't need to know about this little detail" isn't acceptable for Python docs. Little details you don't need to know about add up. -- --Guido van Rossum (home page: http://www.python.org/~guido/)