Python中的装饰器是否与对函数进行函数调用完全相同?

3 投票
1 回答
677 浏览
提问于 2025-04-16 00:10

我原以为这样做

@f
def g():
   print 'hello'

和这样做

def g():
   print 'hello'
g=f(g)

是完全一样的。

但是,我有一段代码,使用了contextlib.contextmanager:

@contextlib.contextmanager
def f():
    print 1
    yield
    print 2
with f:
    print 3

这段代码可以正常工作,并且输出了 1 3 2

当我尝试把它改成

def f():
    print 1
    yield
    print 2
f=contextlib.contextmanager(f)
with f:
    print 3

时,我遇到了 AttributeError: 'function' object has no attribute '__exit__' 的错误。

我到底漏掉了什么呢?是contextlib.contextmanager里有什么特别的地方,还是我对装饰器的理解有误?

1 个回答

5

是的,装饰器其实就像是调用一个函数,然后把返回的结果赋值给一个变量。

在这种情况下出错是因为你没有调用这个函数,所以正确的代码应该是:

def f():
    print 1
    yield
    print 2

f=contextlib.contextmanager(f)
with f():
    print 3

另外,我不太确定你是否测试过代码,因为你提供的装饰器代码也会因为同样的原因出错。

@contextlib.contextmanager
def f():
    print 1
    yield
    print 2
with f:
    print 3

错误信息:

    with f:
AttributeError: 'function' object has no attribute '__exit__'

撰写回答