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

use*_*743 21 python class count decorator exit

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

    "TypeError: __exit__() takes exactly 1 argument (4 given)"
Run Code Online (Sandbox Code Playgroud)

我真的不知道我是怎么给它四个论点的.我的代码看起来像这样:

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
Run Code Online (Sandbox Code Playgroud)

我应该(或不应该)将一些其他参数传递到def 退出函数吗?任何提示或想法将不胜感激.

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

Noa*_*oah 37

__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
Run Code Online (Sandbox Code Playgroud)

然后你可以尝试在你的一个with:块中引发异常并且它会被捕获__exit__().


小智 7

您收到该错误的原因是因为__exit__()需要 3 个参数以及self. 这些都是:

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

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

def __exit__(self, exception_type, exception_value, traceback):
Run Code Online (Sandbox Code Playgroud)

或者

def __exit__(self, *args, **kwargs):
Run Code Online (Sandbox Code Playgroud)

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

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

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