我在使用数据库(或文件)时发现非常方便的一个python功能是您可以为类提供的__enter__
和__exit__
函数。现在通过使用with
语句,您可以确保首先调用此块__enter__
(并且可以打开数据库或文件),并在完成后调用__exit__
(并且您可以关闭数据库或文件。
每次调用Database类中的函数时,我想打开并关闭一个sqlite事务。我可以在每个函数的开头和结尾处执行它,但是因为必须为每个函数完成该类,我想知道,是否有在每个函数调用之前和之后调用的方法?像单元测试中的SetUp和TearDown一样。
答案 0 :(得分:7)
您可以使用饼图装饰器来装饰每个成员函数,例如
@transaction
def insertData(self):
# code
和transaction是一个装饰器,你定义用一个pre和post包装函数。 是的,你必须为每个功能做到这一点。这是一个例子
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
另一种方法是使用元类,如下所示:
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)
这是纯粹的黑魔法,但它有效
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
您通常不想装饰__init__
,并且您可能只想装饰具有特殊名称的方法,因此您可能想要替换
for attributeName, attribute in classDict.items():
if type(attribute) == types.FunctionType:
类似
for attributeName, attribute in classDict.items():
if type(attribute) == types.FunctionType and "trans_" in attributeName[0:6]:
这样,只有trans_whatever的方法才会被转换。