0

我有一个简单的装饰器,输出让我很困惑。

def deco(func):
   def kdeco():
      print("before myfunc() called.")
      func()
      print("  after myfunc() called.")
   return kdeco

@deco
def myfunc():
   print(" myfunc() called.")

myfunc()

before myfunc() called.
 myfunc( deco(myfunc)()) called.
  after myfunc() called.

deco(myfunc)()

before myfunc() called.
before myfunc() called.
 myfunc() called.
  after myfunc() called.
  after myfunc() called.

我知道 myfunc() 的输出,但是 deco(myfunc)() 的输出让我很困惑,为什么 deco(myfunc)() 的输出不能是下面的任何一个?

状态一:

before myfunc() called.
before myfunc() called.
 myfunc() called.
 myfunc() called.
  after myfunc() called.
  after myfunc() called.

状态二:

before myfunc() called.
 myfunc( deco(myfunc)()) called.
  after myfunc() called.
before myfunc() called.
 myfunc( deco(myfunc)()) called.
  after myfunc() called.
4

3 回答 3

4

myfunc本身已经被你的装饰器包裹了。名称myfunc不再指向原始方法,它现在指向的返回值deco(myfunc)

>>> def deco(func):
...    def kdeco():
...       print("before myfunc() called.")
...       func()
...       print("  after myfunc() called.")
...    return kdeco
... 
>>> @deco
... def myfunc():
...    print(" myfunc() called.")
... 
>>> myfunc
<function kdeco at 0x10068cb18>

这是因为@decorator语法与以下内容相同:

def myfunc():
    # body of function
myfunc = deco(myfunc)

所以myfunc已经在生产线before ..,然后.. called,然后after ..。现在你再把它包起来。包装器打印before ..,调用包装器myfunc(本身已经包装),它打印before ..,然后.. called,然后after ..,然后包装器打印after ..

在图表中:

call wrapped myfunc():
    kdeco: "before .."
    call original myfunc()
        original myfunc: ".. called"
    kdeco: "after .."

call deco(myfunc)():
    kdeco: "before .."
    call wrapped myfunc():
        kdeco: "before .."
        call original myfunc()
            original myfunc: ".. called"
        kdeco: "after .."
    kdeco: "after .."
于 2013-01-16T00:26:30.520 回答
1

装饰函数只被调用一次,因此它不能声称被调用了两次。

于 2013-01-16T00:24:36.180 回答
1

装饰器实际上只是您可以手动执行的操作的捷径。这段代码:

@deco
def myfunc():
    print(" myfunc() called.")

相当于:

def myfunc():
    print(" myfunc() called.")
myfunc = deco(myfunc)

为了讨论这个问题,假设原件仍然可用original_myfunc(尽管实际上它不是)。

所以,当你这样做时:

deco(myfunc)()

你最终调用的是:

deco(deco(original_myfunc))()

如果你追溯它,应该很明显为什么它会打印你所期望的。但无论如何,让我们做这个练习。

首先,您调用deco(original_myfunc),它会执行以下操作:

def kdeco():
   print("before myfunc() called.")
   original_myfunc()
   print("  after myfunc() called.")

返回 kdeco

这样就返回了一个打印“之前”的函数,调用original_myfunc,然后打印“之后”。

现在我们再次传递deco(original_myfunc)deco它,它会这样做:

def kdeco():
   print("before myfunc() called.")
   deco(original_myfunc)()
   print("  after myfunc() called.")
return kdeco

因此,它返回一个打印“之前”的函数,然后调用deco(original_myfunc)——它本身打印“之前”,调用original_myfunc并打印“之后”——然后打印“之后”。

这就是为什么你得到你所做的输出。

于 2013-01-16T00:26:48.930 回答