Is there a __enter__ and __exit__ equivalent for all functions in a class?
class, function, python
Solution
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.
Problem
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.