__enter__和__exit__如何在Python装饰器类中工作?

时间:2014-03-14 23:02:46

标签: python class count decorator exit

我试图创建一个装饰器类来计算调用函数的次数,但是我收到的错误消息显示:

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

我真的不知道我是如何给出四个论点的。我的代码如下所示:

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 退出功能吗?任何提示或想法将不胜感激。

顺便说一下,我的代码行说“打印' f count =',f.count"似乎是在输出内存地址而不是值,但这是一个完全不同的问题。

2 个答案:

答案 0 :(得分:35)

__exit__()方法应该接受有关with:块中出现的异常的信息。请参阅here

您的代码的以下修改有效:

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:个区块中引发异常,然后它会被__exit__()抓住。

答案 1 :(得分:1)

您收到该错误的原因是 __exit__() 需要 3 个参数和 self。它们是:

  1. 异常类型
  2. exception_value
  3. 追溯

您可以通过两种方式定义 __exit__() 方法:

def __exit__(self, exception_type, exception_value, traceback):

def __exit__(self, *args, **kwargs):

with 语句支持由使用 __enter__()__exit__() 方法对实现的上下文管理器定义的运行时上下文的概念。请访问此 link 了解详细信息。

__enter__() 方法将进入运行时上下文并返回此对象或与运行时上下文相关的另一个对象。

__exit__() 方法将退出运行时上下文并返回一个布尔标志,指示是否应抑制发生的任何异常。这些参数的值包含有关抛出异常的信息。 如果值等于 None 表示没有抛出异常。