python中的装饰者困惑了我

时间:2013-01-16 00:19:37

标签: python decorator python-decorators

我有一个简单的装饰,输出混淆了我。

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.

3 个答案:

答案 0 :(得分: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 .."

答案 1 :(得分:1)

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

答案 2 :(得分: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

因此返回一个打印“before”的函数,调用original_myfunc,然后打印“after”。

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

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

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

这就是你获得输出的原因。