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