Passing connections to functions using a decorator
Posted by Daniele Varrazzo
on October 22, 2010
Tagged as
recipe
In many script I write, there are functions requiring database operations. Every time I need them, I try to write such code in functions like:
@with_connection
def do_some_job(cnn, arg1, arg2=None):
cur = cnn.cursor()
cur.execute(SQL, (arg1, arg2)) # or something else
do_some_job(42, arg2='hi')
There are many benefits for this pattern:
- the client code doesn't depend on the details of connection creation and disposal
- the client code doesn't either need to deal with the session management: no more pending transactions...
- connection management is consistent throughout all the functions.
Implementation of such a decorator is straightforward, but because of the many possible variation it never made its way into a proper library. It goes something like:
def with_connection(f):
def with_connection_(*args, **kwargs):
# or use a pool, or a factory function...
cnn = psycopg.connect(DSN)
try:
rv = f(cnn, *args, **kwargs)
except Exception, e:
cnn.rollback()
raise
else:
cnn.commit() # or maybe not
finally:
cnn.close()
return rv
return with_connection_
There may be many variations: you may use use a connection pooler, you may want a read only or an autocommit connection... Best strategy I've found is just to keep one or a few decorator like this in the project I'm working at and use it for a consistent management of the database communications in the desired scope (the project, a package, a module...)
Comments (2 posted).
Feel free to add a new comment. You can use reST syntax.
Dan Korostelev
Oct. 29, 2010, 2:32 p.m.
Another approach that I like even more is context managers. Something like this:
note: reformatted after introduced reST comments.
and the context manager itself is something like:
piro
Oct. 29, 2010, 4:11 p.m.
Thank you, Dan.
I've introduced reST syntax in comments (this is pretty much the Django comments system out of the box) and I've reformatted your comment: I hope you don't mind.