I don't intend to simply waste your time, but: has it occurred to you too, while using Python's with
statement that it really is contrary to the 5th line of "The Zen of Python" that goes "Flat is better than nested"? Can any enlightened Python guru share me some of their insights on this?
(I always find that one more level of indentation pops up in my code every time I use with
instead of f.close()
... and it's not like I'm not gonna use try: ... finally: ...
anyways and thus the benefits of with
still elude me, even as I grow to like and understand Python more and more...)
@glglgl (sorry, I can't find a way to write code in comments):
yes, but if you go the with
way, your code becomes:
try:
with file(...) as f:
...
except IOError:
...
...and using just with without the try
is what people end up doing in the type of hacky "one use" code where they use f.close()
instead of with anyways (which is bad because the file may not be closed if an exception is thrown before their f.close()
), so for "hacky" code people just don't use with
because, I don't know, I guess they just find it too "fancy" and for well structured code it doesn't bring any benefits anyways, so it seems to me there's no real world use case left for it... that was my pondering about really.
Yes, The Zen of Python states "Flat is better than nested", however it is not the only characteristic we care about; it also states "Simple is better than complex". The beauty of
with
is that it actually adheres to both of those principles as I will explain below.Any time you find yourself in philosophical pondering about a feature in Python it's probably worth looking up the Python Enhancement Proposals (PEPs) to read about the motivation behind the feature. In this case PEP 343 -- The "with" Statement says it up front in the abstract:
Factoring out
try/finally
statements makes the code simpler and more readable.PEP 343 goes deeper than providing some simplistic syntactic sugar, however. It establishes a context manager protocol:
Using the context manager protocol, API writers can help hide complexity and ensure correct acquisition/release of resources in a multi-threaded context.
But the real beauty of the
with
statement is shown in Example 12 of PEP 343 which explains that:Using the
nested()
context manager you can take code that looks like this:and turn it into this:
Note that
nested()
was introduced in Python 2.5, but as of version 2.7 it is deprecated in favor of this multiple context manager syntactic form:Clearly not only is this simpler and more readable, but it is much more flat than nested. Thus, using
with
is following the path of 無爲 :)UPDATE: In response to comments on Simeon Visser's answer here is an example of when you might use multiple context managers to open more than one file at once, when you want to zip the contents of two (or more) files together such that if opening one of the files fails it will make the whole thing fail and properly close each file that was opened:
Run this example twice; once as a root and once as normal user. Presuming you save this file as
ziptogether.py
first try invoking it as root withsudo python ziptogether.py
and it will succeed, but invoking it as a normal user withpython ziptogether.py
will fail because you don't have permissions to read/etc/shadow
. When it fails the context manager will ensure that the files that were successfully opened before the failure are properly closed when execution moves outside the scope of thewith
statement.