I came across the Python with
statement for the first time today. I\'ve been using Python lightly for several months and didn\'t even know of its existence! G
The Python with
statement is built-in language support of the Resource Acquisition Is Initialization idiom commonly used in C++. It is intended to allow safe acquisition and release of operating system resources.
The with
statement creates resources within a scope/block. You write your code using the resources within the block. When the block exits the resources are cleanly released regardless of the outcome of the code in the block (that is whether the block exits normally or because of an exception).
Many resources in the Python library that obey the protocol required by the with
statement and so can used with it out-of-the-box. However anyone can make resources that can be used in a with statement by implementing the well documented protocol: PEP 0343
Use it whenever you acquire resources in your application that must be explicitly relinquished such as files, network connections, locks and the like.
points 1, 2, and 3 being reasonably well covered:
4: it is relatively new, only available in python2.6+ (or python2.5 using from __future__ import with_statement
)
I would suggest two interesting lectures:
1.
The with
statement is used to wrap the execution of a block with methods defined by a context manager. This allows common try...except...finally
usage patterns to be encapsulated for convenient reuse.
2. You could do something like:
with open("foo.txt") as foo_file:
data = foo_file.read()
OR
from contextlib import nested
with nested(A(), B(), C()) as (X, Y, Z):
do_something()
OR (Python 3.1)
with open('data') as input_file, open('result', 'w') as output_file:
for line in input_file:
output_file.write(parse(line))
OR
lock = threading.Lock()
with lock:
# Critical section of code
3.
I don't see any Antipattern here.
Quoting Dive into Python:
try..finally is good. with is better.
4.
I guess it's related to programmers's habit to use try..catch..finally
statement from other languages.
Another example for out-of-the-box support, and one that might be a bit baffling at first when you are used to the way built-in open()
behaves, are connection
objects of popular database modules such as:
The connection
objects are context managers and as such can be used out-of-the-box in a with-statement
, however when using the above note that:
When the
with-block
is finished, either with an exception or without, the connection is not closed. In case thewith-block
finishes with an exception, the transaction is rolled back, otherwise the transaction is commited.
This means that the programmer has to take care to close the connection themselves, but allows to acquire a connection, and use it in multiple with-statements
, as shown in the psycopg2 docs:
conn = psycopg2.connect(DSN)
with conn:
with conn.cursor() as curs:
curs.execute(SQL1)
with conn:
with conn.cursor() as curs:
curs.execute(SQL2)
conn.close()
In the example above, you'll note that the cursor
objects of psycopg2
also are context managers. From the relevant documentation on the behavior:
When a
cursor
exits thewith-block
it is closed, releasing any resource eventually associated with it. The state of the transaction is not affected.
See PEP 343 - The 'with' statement, there is an example section at the end.
... new statement "with" to the Python language to make it possible to factor out standard uses of try/finally statements.
The with statement works with so-called context managers:
http://docs.python.org/release/2.5.2/lib/typecontextmanager.html
The idea is to simplify exception handling by doing the necessary cleanup after leaving the 'with' block. Some of the python built-ins already work as context managers.