One functionality of python that I found very handy when working with databases (or files) are the __enter__
and __exit__
functions you can give to a class. Now by using the with
statement you can make sure that in this block __enter__
is first called (and you can open the database or file) and after it's done __exit__
is called (and you can close a database or file.
I want to open and close a sqlite transaction every time a function from my Database class is called. I can do it at the start and end of every function, but since it has to be done for every function is that class, I was wondering, are there methods that get called before and after each function call? Like SetUp and TearDown in unittesting.
You can decorate every member function with a pie decorator, something like
@transaction
def insertData(self):
# code
and transaction is a decorator you define to wrap the function with a pre and post. Yes, you have to do it for every function. Here is an example
def transaction(f):
def pre():
print "pre transaction"
def post():
print "post transaction"
def wrapped(*args):
pre()
f(*args)
post()
return wrapped
class Foo(object):
def __init__(self):
print "instantiating"
def doFoo(self):
print "doing foo"
@transaction
def doBar(self, value):
print "doing bar "+str(value)
@transaction
def foofunc():
print "hello"
foofunc()
f=Foo()
f.doFoo()
f.doBar(5)
.
stefanos-imac:python borini$ python decorator.py
pre transaction
hello
post transaction
instantiating
doing foo
pre transaction
doing bar 5
post transaction
The alternative is that you use a metaclass, like this:
import types
class DecoratedMetaClass(type):
def __new__(meta, classname, bases, classDict):
def pre():
print "pre transaction"
def post():
print "post transaction"
newClassDict={}
for attributeName, attribute in classDict.items():
if type(attribute) == types.FunctionType:
def wrapFunc(f):
def wrapper(*args):
pre()
f(*args)
post()
return wrapper
newAttribute = wrapFunc(attribute)
else:
newAttribute = attribute
newClassDict[attributeName] = newAttribute
return type.__new__(meta, classname, bases, newClassDict)
class MyClass(object):
__metaclass__ = DecoratedMetaClass
def __init__(self):
print "init"
def doBar(self, value):
print "doing bar "+str(value)
def doFoo(self):
print "doing foo"
c = MyClass()
c.doFoo()
c.doBar(4)
This is pure black magic, but it works
stefanos-imac:python borini$ python metaclass.py
pre transaction
init
post transaction
pre transaction
doing foo
post transaction
pre transaction
doing bar 4
post transaction
You normally don't want to decorate the __init__
, and you may want to decorate only those methods with a special name, so you may want to replace
for attributeName, attribute in classDict.items():
if type(attribute) == types.FunctionType:
with something like
for attributeName, attribute in classDict.items():
if type(attribute) == types.FunctionType and "trans_" in attributeName[0:6]:
This way, only methods called trans_whatever will be transactioned.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With