On Nov 15, 2019, at 04:37, Jonathan Fine <jfine2...@gmail.com> wrote:
> 
> 
> Serhiy suggests
> https://docs.python.org/3/library/contextlib.html#contextlib.ExitStack
> >>> with ExitStack() as stack:
> >>>       files = [stack.enter_context(open(fname)) for fname in filenames]
> 
> A simpler alternative, for the OP's original post, could be:
> >>> with ExitMap(open, ['a', 'b', 'c']) as a, b, c:
> >>>     pass
> where ExitMap(*args) is equivalent to helper(map(*args)). Of course, using 
> ExitStack is the easy way to code ExitMap.

The advantage of your ExitMap over helper (besides being shorter, and 
conceptually simpler) is that it’s never misleading.

    with helper(open(fn) for fn in (fna, fnb, fnc)) as a, b, c:

This is fine. If open(fnb) raises, helper has already stacked up open(fna) and 
can exit it. But change the genexpr to a listcomp:

    with helper([open(fn) for fn in (fna, fnb, fnc)]) as a, b, c:

This looks the same, and seems fine if you don’t test error cases, but if 
open(fnb) fails, helper never gets called so nothing gets stacked up so 
open(fna) leaks.

And calling it with an iterable you create out-of-line can make it even more 
confusing because it’s not as clear where to look when you accidentally make 
the iterable not lazy. Not to mention that it could even be a properly lazy 
Iterator but one that needs to be fully consumed for your program logic (not an 
issue for a simple map over a tuple of strings), and that would be an even more 
subtle bug.

If you could clearly document and/or test for the requirements, maybe helper 
would be useful. But your ExitMap doesn’t rely on you correctly building the 
right iterator; it builds the Iterator itself, and doesn’t expose parts that 
can be misused. So it’s trivial to document, and to learn and use.

It still seems like overkill for the case of “how do I get parens somewhere 
around a bunch of open calls so I can write a multiline with statement”, and 
I’m not sure how often it would be useful in other cases. But it seems like 
it’s at least worth building for your personal toolbox and keeping track of how 
often it comes up (and how much nicer it makes things), and maybe publishing it 
to PyPI or submitting it to contextlib2 so more people will do the same.

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

Reply via email to