我有一个简单的装饰,输出混淆了我。
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.
答案 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
,然后打印“之后” - 然后打印“之后”
这就是你获得输出的原因。