The final release of python 2.5 is out! The list of what’s new is pretty impressive, but I’m especially happy to have the new “with” statement. Ruby has block methods, or closures, which can be used for doing very clean setup/cleanup. While full-blown Anonymous block statements were rejected from Python, the new “with” statement handles the part I care about: making it easier to write code that works correctly in the case of failures.
The 3 typical use cases are a file that needs to be closed, a lock that needs to be released, and and a database transaction that needs to be either committed or rolled back. The database case is the most interesting, since you need to handle success and failure differently, and before version 2.5 python would not allow you to have try/except/finally. You had to pick either try/except or try/finally. Python 2.5 also provides a unified try/except/finally, but the “with” statement is easier to write, and easier to read.
I’ve borrowed an example of what user code would look like for a database connection using the new “with” statement from the python docs. The idea is that the block of code should run, and then the transaction should either be committed or rolled back depending on whether the block exited normally or with an exception:
db_connection = DatabaseConnection()
with db_connection as cursor:
cursor.execute('insert into ...')
cursor.execute('delete from ...')
# ... more operations ...
In order for this to work, it looks like the classes that you are working with need to properly support a context manager which defines what should happen for success and error. But, not all classes will need to implement a full blown context manager, the contextlib module allows for an easy way to add support to existing objects without the need to write a new class.
from contextlib import contextmanager
@contextmanager
def db_transaction (connection):
cursor = connection.cursor()
try:
yield cursor
except:
connection.rollback()
raise
else:
connection.commit()
db = DatabaseConnection()
with db_transaction(db) as cursor:
...
This was one area where Ruby code was much cleaner than Python, so it’s great to see the new functionality. It’s pretty hard for me to write code which doesn’t touch a file, a database, or threads, so it will be used a lot.