[Python-Dev] Multiline with statement line continuation (original) (raw)

yoav glazner yoavglazner at gmail.com
Wed Aug 13 19:08:51 CEST 2014


On Aug 13, 2014 7:04 PM, "Akira Li" <4kir4.1i at gmail.com> wrote:

Nick Coghlan <ncoghlan at gmail.com> writes: > On 12 August 2014 22:15, Steven D'Aprano <steve at pearwood.info> wrote: >> Compare the natural way of writing this: >> >> with open("spam") as spam, open("eggs", "w") as eggs, frobulate("cheese") as cheese: >> # do stuff with spam, eggs, cheese >> >> versus the dynamic way: >> >> with ExitStack() as stack: >> spam, eggs = [stack.entercontext(open(fname), mode) for fname, mode in >> zip(("spam", "eggs"), ("r", "w")] >> cheese = stack.entercontext(frobulate("cheese")) >> # do stuff with spam, eggs, cheese > > You wouldn't necessarily switch at three. At only three, you have lots > of options, including multiple nested with statements: > > with open("spam") as spam: > with open("eggs", "w") as eggs: > with frobulate("cheese") as cheese: > # do stuff with spam, eggs, cheese > > The "multiple context managers in one with statement" form is there > solely to save indentation levels, and overuse can often be a sign > that you may have a custom context manager trying to get out: > > @contextlib.contextmanager > def dish(spamfile, eggfile, topping): > with open(spamfile), open(eggfile, 'w'), frobulate(topping): > yield > > with dish("spam", "eggs", "cheese") as spam, eggs, cheese: > # do stuff with spam, eggs & cheese > > ExitStack is mostly useful as a tool for writing flexible custom > context managers, and for dealing with context managers in cases where > lexical scoping doesn't necessarily work, rather than being something > you'd regularly use for inline code. > > "Why do I have so many contexts open at once in this function?" is a > question developers should ask themselves in the same way its worth > asking "why do I have so many local variables in this function?" Multiline with-statement can be useful even with two context managers. Two is not many. Saving indentations levels along is a worthy goal. It can affect readability and the perceived complexity of the code. Here's how I'd like the code to look like: with (open('input filename') as inputfile, open('output filename', 'w') as outputfile): # code with list comprehensions to transform input file into output file Even one additional unnecessary indentation level may force to split list comprehensions into several lines (less readable) and/or use shorter names (less readable). Or it may force to move the inline code into a separate named function prematurely, solely to preserve the indentation level (also may be less readable) i.e., with ... as inputfile: with ... as outputfile: ... #XXX indentation level is lost for no reason with ... as infile, ... as outfile: #XXX shorter names ... with ... as inputfile: with ... as outputfile: transform(inputfile, outputfile) #XXX unnecessary function And (nested() can be implemented using ExitStack): with nested(open(..), open(..)) as (inputfile, outputfile): ... #XXX less readable Here's an example where nested() won't help: def getintegers(filename): with (open(filename, 'rb', 0) as file, mmap.mmap(file.fileno(), 0, access=mmap.ACCESSREAD) as mmapped_file): for match in re.finditer(br'\d+', mmappedfile): yield int(match.group()) Here's another: with (open('log'+'some expression that generates filename', 'a') as logfile, redirectstdout(logfile)): ... Just a thought, would it bit wierd that: with (a as b, c as d): "works" with (a, c): "boom" with(a as b, c): ?

-- Akira


Python-Dev mailing list Python-Dev at python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/yoavglazner%40gmail.com -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.python.org/pipermail/python-dev/attachments/20140813/0f7908cc/attachment-0001.html>



More information about the Python-Dev mailing list