web-dev-qa-db-ja.com

__enter__と__exit__はPythonデコレータクラスでどのように機能しますか?

関数が呼び出された回数をカウントするデコレータクラスを作成しようとしていますが、次のようなエラーメッセージが表示されます。

    "TypeError: __exit__() takes exactly 1 argument (4 given)"

どうやって4つの議論をしているのか本当にわかりません。私のコードは次のようになります:

class fcount2(object):
    __instances = {}
    def __init__(self, f):
        self.__f = f
        self.__numcalls = 0
        fcount2.__instances[f] = self

    def __call__(self, *args, **kwargs):
        self.__numcalls += 1
        return self.__f(*args, **kwargs)

    def __enter__(self):
        return self

    def __exit__(self):
        return self

    @staticmethod
    def count(f):
        return fcount2.__instances[self.__f].__numcalls


@fcount2
def f(n):
    return n+2

for n in range(5):
    print f(n)   
print 'f count =',f.count

def foo(n):
    return n*n

with fcount2(foo) as g:
    print g(1)
    print g(2)
print 'g count =',g.count
print 'f count =',f.count

with fcount2(f) as g:
    print g(1)
    print g(2)
print 'g count =',g.count
print 'f count =',f.count

with f:
    print f(1)
    print g(2)
print 'g count =',g.count
print 'f count =',f.count

Def exit関数に渡す必要がある(または渡してはならない)他のパラメーターはありますか?ヒントやアイデアをいただければ幸いです。

余談ですが、「print'f count = '、f.count」というコード行は、値ではなくメモリアドレスを出力しているように見えますが、これはまったく別の問題です。

22
user3402743

__exit__()メソッドは、_with:_ブロックで発生する例外に関する情報を受け入れる必要があります。 ここ を参照してください。

コードの次の変更は機能します。

_def __exit__(self, exc_type, exc_value, tb):
    if exc_type is not None:
        traceback.print_exception(exc_type, exc_value, tb)
        # return False # uncomment to pass exception through

    return True
_

次に、_with:_ブロックの1つで例外を発生させてみると、__exit__()でキャッチされます。

40
Noah