On 2019-11-18 10:59 p.m., Andrew Barnert wrote:
On Nov 18, 2019, at 16:35, Soni L. <fakedme...@gmail.com> wrote:
> > >> On 2019-11-18 5:22 p.m., Soni L. wrote: >> >> >>> On 2019-11-18 5:13 p.m., Andrew Barnert via Python-ideas wrote:
>>>> On Nov 18, 2019, at 10:51, Random832 <random...@fastmail.com> wrote:
>>> > > On Mon, Nov 18, 2019, at 12:46, Paul Moore wrote:
>>> >> But open() isn't designed *just* to be used in a with statement. It
>>> >> can be used independently as well. What about
>>> >> >>    f = open(filename)
>>> >>    header = f.readline()
>>> >>    with f:
>>> >>        # use f
>>> >> >> The open doesn't "create a future need to call __exit__". It *does*
>>> >> require that the returned object gets closed at some stage, but you
>>> >> can do that manually (for example, if "header" in the above is "do not
>>> >> process", maybe you'd close and return early). > > sure, but "need to call close" 
is just a different spelling of "need to call __exit__".
>>> > >> 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().
>>> > > I would say open() is arguably a wart. Had context managers existed in the 
language all along, it should not be possible to do anything that creates an open-ended future 
requirement to do something (i.e. "require that the returned object gets closed at some 
stage") without either using a with statement or writing code to manually call __enter__ and 
__exit__. The likely most common case being a class that holds an open file, which should really have 
its own context manager that forwards to the file's.
>>> > > to that end, open() could look something like this:
>>> > > def open(*a,**k):
>>> >   cm = opened(*a, **k)
>>> >   f = cm.__enter__()
>>> >   f.close = cm.__exit__
>>> >   return f
>>> >>> I think in that hypothetical language you might want a generic “releaser” function, or method on all cms, or even special syntax, to turn any cm into something that you’ll take care of closing later manually (usually, but not necessarily, by using the closing cm on it in a different lexical context that you end up passing the released cm to). >>> >>> (I think C++ smart pointers might be relevant here, or maybe something from Rust, although I haven’t thought it through in much detail.) >> >> could we tweak open() so it doesn't raise immediately? this would make it play nicer with __enter__ but would probably break some things. this would make open() itself "never" fail. > > let me ask again: can we make it so open() never fails, instead returning a file that can be either "open", "closed" or "errored"? > > operations on "errored" files would, well, raise. > > more specifically, __enter__ would raise. > > thus, `with (open("foo"), open("bar")) as (foo, bar):` would actually work.

Sure, that could work. After all, when POSIX open returns -1, if you don’t 
check it explicitly and just start calling functions, they all fail with 
EBADFD. (Although, being C, you have to check _those_ failures explicitly—but 
that wouldn’t be an issue for Python.)

It seems like it would be just as much of a breaking change as everything else 
suggested here. Plenty of code expects open to fail immediately, and will do 
the wrong thing if it doesn’t, unless it’s all rewritten to use with 
immediately, and to use tuples as context managers rather than any other idiom 
when opening multiple files. Also, does every third-party (or maybe even 
stdlib?) file-like object that’s managing a resource have to change to not open 
the socket or whatever until you enter it?

No. They have to change to not *raise* until you either enter it, or call some other method on it.


But by the same token, I don’t think it breaks any _more_ code than the other 
ideas, and maybe it’s simpler than some of them?

But doesn’t that raise the same issue discussed in the other subthread of how 
you handle cases where you don’t want a context manager anywhere at all? Do you 
have to change them all to explicitly call __enter__, and then call __exit__ 
instead of close? Or do we add a really_open method paired with close for those 
cases? Or can we just ban all such cases and say that you’re always supposed to 
find a way to wrap them in a cm somehow?

No. If it's "errored" then close will raise, but otherwise it'll close. No need to explicitly call __enter__. Everything would work as it does today except open() itself wouldn't immediately raise but defer the raise to any method call - be that __enter__, read, close, whatever.

If you don't want to use a cm, wrap the reads/writes/close in try/except.


One more thing: what happens when I, e.g., call open on an fd? Today we can 
expect that as soon as we do that, the file object owns the file handle. Either 
you’d change that so the file object doesn’t own the file handle until it’s 
entered, or you’d make open inconsistent about whether it owns a file object 
before enter, which could be confusing.

I don't know? Can open(fd) raise currently? If so, it'd stop raising, and would defer the raise to any method call, but otherwise open the fd immediately.




_______________________________________________
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/YMKX6L6OFRAJRWCEO6LSPQBXOS2K4P6C/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to