[Python-Dev] PEP 377 - allow __enter__() methods to skip the statement body

Guido van Rossum guido at python.org
Mon Mar 16 19:33:33 CET 2009


On Mon, Mar 16, 2009 at 11:26 AM, Steven Bethard
<steven.bethard at gmail.com> wrote:
> On Mon, Mar 16, 2009 at 11:06 AM, Guido van Rossum <guido at 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 at 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/)


More information about the Python-Dev mailing list