On Mon, 18 Nov 2019 at 17:46, Paul Moore <p.f.mo...@gmail.com> wrote:
>
> On Mon, 18 Nov 2019 at 17:17, Oscar Benjamin <oscar.j.benja...@gmail.com> 
> wrote:
> > The problem with a misbehaving context manager is that it creates a
> > future need to call __exit__ before it has been passed to a with
> > statement or any other construct that can guarantee to do that.
>
> You seem to be focusing purely on the usage
>
>     with open(filename) as f:
>         # use f
>
> But open() isn't designed *just* to be used in a with statement.
> It can be used independently as well.

That's the problem I think. The context manager for closing the file
is conflated as an object with the file object and its methods when
they don't need to be the same object. This was considered in PEP 343:
"""
The problem is that in PEP 310, the result of calling EXPR is assigned
directly to VAR, and then VAR's __exit__() method is called upon exit
from BLOCK1. But here, VAR clearly needs to receive the opened file,
and that would mean that __exit__() would have to be a method on the
file.
"""
The discussion there shows that part of the design of the with
statement was precisely so that it would not be necessary for the file
object itself to *be* the context manager because __enter__ can return
a different object.

> What about
>
>     f = open(filename)
>     header = f.readline()
>     with f:
>         # use f

I would naturally rewrite that as

with open(filename) as f:
    header = f.readline()
    # use f

which would work just as well with opened instead of open. The opened
function returns a context manager whose __enter__ method returns the
file object which then has the corresponding file object methods.

[snip]
> You can wrap open() in a context manager like opened() that *does*
> work like that, but it's not the only way to write context managers.
> Certainly, nested() can't be written to safely work with the full
> generality of context managers as we currently have them, but as I
> said that's a trade-off.

I think that nested was fine but in combination with open it was prone
to misuse. By the time with/contextlib etc had shipped in 2.5 it was
easier to blame nested (which also had other flaws) so it took the
fall for open.

> Maybe I should ask the question the other way round. If we had
> opened(), but not open(), how would you write open() using opened()?
> It is, after all, easy enough to write opened() in terms of open().

The idea would be to have both so I don't think it matters but if you
had opened and wanted to build open out of it then you could do:

def open(*args):
    return opened(*args).__enter__()

> Anyway, I already said that where you choose to draw the line over
> what a context manager is (assuming you feel that the current
> definition is wrong), depends on your perspective.

It's not so much that the definition is wrong. It just isn't really
defined and that makes it difficult to do anything fancy with multiple
context managers. You need protocol contraints on both sides to be
able to build useful utilities/patterns. The bar set for nested was
that it should be able to recover from errors before it even gets
called!

> So I'm not trying
> to persuade you that I'm right over this. Unless this turns into a PEP
> to change the language (and I think it would need a PEP) it's just
> speculation and collecting opinions, so you have mine ;-)

A PEP seems premature as I'm not sure I have any clear solution...

--
Oscar
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/BXJZFZ3BFTI6KL2YR2W732YKSGZLKBM7/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to