On Nov 19, 2019, at 18:53, Oscar Benjamin <oscar.j.benja...@gmail.com> wrote:
> 
> On Wed, 20 Nov 2019 at 02:36, Richard Damon <rich...@damon-family.org> wrote:
>> 
>> If I understand it right, an eager context manager (like open currently
>> is) allows itself to be used somewhat optionally, and not need to be in
>> a with statement. A lazy context manager on the other hand, seems to be
>> assuming that it will be used in a with statement (or something
>> similar), as it is putting off some important work until it sees it is
>> in there.
>> 
>> It impetus for this seems to be to make a cleaner syntax for a with
>> statement managing multiple resources through context managers, if we
>> only need simple recovery (the built in provided by the context
>> manager). It may be at the cost of making more complex (and explicit)
>> handling of conditions for current (or possible future) 'eager'
>> managers. For example, if open doesn't actually open the file, but only
>> prepares to open, then the use of a file outside a with becomes more
>> complicated if we want somewhat precise control over the file.
> 
> The idea would be (or rather would have been) that open still does the
> same thing it did before and returns a file object with the usual
> methods. However that file object would *not* be a context manager. If
> you wanted a context manager for the file then you would have used
> opened (from PEP 343) rather than open and opened would give a context
> manager whose __enter__ would return the same file object that open
> otherwise returns. So it doesn't make other uses of the file object
> more complicated except that you choose whether to call open or opened
> depending on how you want to use the file.

Would you also have added sqlite3.connected, mmap.mmapped, socket.madefile, 
requests.got (this name scheme doesn’t extend as well as I thought it would…), 
etc.?

At first it seems like a good idea, but ultimately it means you need two 
different functions or methods for every kind of resource.

Maybe a generic helper is a better idea. For the 80% case (where enter just has 
to call the function and stash and return the result, and exit just calls a 
close method on that result), instead of this:

    with closing(urlopen(url)) as page:

… you do this:

    with context(urlopen, url) as page:

… which gives you a lazy context manager that doesn’t call urlopen until enter.

And for cases where the exit isn’t as simple as calling close, but is simple 
enough to just be a function call, and where the enter function doesn’t take an 
exit kwarg:

    with context(FilesCache, exit=FilesCache.shutdown) as fc:

For anything more complicated you still have to write a custom context manager, 
but that’s not a huge deal considering how rare it is.

Now you don’t need opened and mmapped and so on; if you are calling one of them 
repeatedly, just define it locally:

    opened = partial(context, open)

More importantly, you don’t need files, db connections, network requests, 
mmaps, and other resources to be context managers, you just need them to be 
compatible with context (which most of them already are, and even more would be 
if there were a concrete advantage to it). So there’s no point in eager context 
managers—sure, someone could go out of their way to write one, but then you 
probably could get away with saying that it’s “broken”, unlike today.

This is still more verbose than current Python, and passing a function and its 
args doesn’t look as nice as just calling the function—but remember that you 
can still trivially partial any resource constructor you plan to context manage 
repeatedly. (And if that’s not good enough, you could elevate building and 
entering a context manager around a construction expression into syntactic 
sugar, but I doubt that would be needed.)

But unless you have a time machine back to 2007, I still don’t think this is at 
all feasible, because of all of the code that would have to change, including 
half the existing third-party libraries that provide context managers and even 
more applications that rely on eager context manager behavior. So we’re still 
not talking about an idea for Python here. The idea in my other email, 
providing a wrapper to turn eager context managers lazy and an ABC to 
distinguish them and so on, may not be nearly as clean, but it seems a lot more 
feasible.

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

Reply via email to