4

在处理数据库(或文件)时,我发现 python 的一个非常方便的功能是你可以给类提供的__enter__和函数。__exit__现在通过使用该with语句,您可以确保在此块__enter__中首先调用(并且您可以打开数据库或文件)并在它完成后__exit__调用(并且您可以关闭数据库或文件。

每次调用我的数据库类中的函数时,我都想打开和关闭一个 sqlite 事务。我可以在每个函数的开头和结尾都这样做,但是由于必须为每个函数都做那个类,我想知道,是否有在每个函数调用之前和之后调用的方法?就像单元测试中的 SetUp 和 TearDown 一样。

4

1 回答 1

8

您可以使用 pie 装饰器来装饰每个成员函数,例如

@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 的方法才会被处理。

于 2012-05-09T14:39:01.420 回答