On Mon, 18 Nov 2019 at 11:12, Oscar Benjamin email@example.com wrote:
I am proposing the root of the problem here is the fact that open acquires its resource (the opened file descriptor) before __enter__ is called. This is what I mean by a context manager that "misbehaves". If there was a requirement on context managers that __exit__ cleans up after __enter__ and any resource that needs cleaning up should only be acquired in __enter__ then there would never have been a problem with nested.
What I am saying is that conceived as a context manager the object returned by open misbehaves. I think that not just nested but a number of other convenient utilities and patterns could have been possible if opened has been used instead of open and if context managers were expected to meet the constraint: """ There should be no need to call __exit__ if __enter__ has not been called. """ Of course a lot of time has passed since then and now there are probably many other misbehaving context managers so it might be too late to do anything about that.
Hi Oscar, Thanks for the explanation. I see what you mean now, and that *was* something I got from the previous discussion, it's just that I guess I'm so used to the current behaviour that I never really thought of it as "misbehaviour". I'm not 100% convinced that there aren't edge cases where even your strengthened requirements on a context manager might not be enough. For example, if __enter__ is called, but raises an exception, is calling __exit__ required then? Consider
@contextmanager def open_2_files(): f = open("file1") g = open("file2") try: yield (f,g) finally: g.close() f.close()
That meets your criterion, but if open("file2") fails, you're still in a mess. Of course, that's a toy example, and could be written to fix that, and we could even close that loophole by saying "a context manager should only manage one resource", but we can probably carry on down that route for quite a while (and "should only manage one resource" is not actually correct - the whole *point* of something like nested() would be to manage multiple resources).
So thanks for your explanation, which I appreciate. But I'm not sure "tightening up" the requirements on context managers is really necessary - it will always be a balance between simplicity and catching all the edge cases, and I don't think the case has been proved that the current design got that balance wrong (it'll always be a matter of personal opinion, to an extent, though, so debates like this will probably continue happening).