On 12 August 2014 22:15, Steven D'Aprano <[email protected]> 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.enter_context(open(fname), mode) for fname, mode in
> zip(("spam", "eggs"), ("r", "w")]
> cheese = stack.enter_context(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(spam_file, egg_file, topping):
with open(spam_file), open(egg_file, '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?"
Regards,
Nick.
--
Nick Coghlan | [email protected] | Brisbane, Australia
_______________________________________________
Python-Dev mailing list
[email protected]
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com