4

データベース(またはファイル)を操作するときに非常に便利だと思ったPythonの機能の1つは、クラスに提供できる関数__enter__と関数です。__exit__これで、ステートメントを使用しwithて、このブロック__enter__で最初に呼び出され(データベースまたはファイルを開くことができ)、完了後に__exit__呼び出される(データベースまたはファイルを閉じることができる)ことを確認できます。

Databaseクラスの関数が呼び出されるたびにsqliteトランザクションを開いたり閉じたりしたい。すべての関数の開始時と終了時に実行できますが、すべての関数に対して実行する必要があるので、そのクラスであるため、各関数呼び出しの前後に呼び出されるメソッドはありますか?ユニットテストのSetUpやTearDownのように。

4

1 に答える 1

8

すべてのメンバー関数をパイデコレータで装飾できます。

@transaction
def insertData(self):
    # code

トランザクションは、関数を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 に答える