想象一下:
def b1(fnc):
print "b1"
return fnc
@b1
def a1():
print "a1"
if __name__ == "__main__":
a1() # will print b1 a1
所以,当我使用@b1
时,a1会转到a1 = b1(a1)
,对吧?
然后,当我说:
a1()
这转向:
b1(a1)
然后进入:
print "b1"
return fnc
在哪里/谁正在调用fnc?我有一种感觉,我问的是一个非常愚蠢的问题,但我想明白。
答案 0 :(得分:7)
装饰器只执行一次。它需要一个可调用对象并返回一个可调用对象。它返回的对象用于代替a1
。
换句话说,b1
在定义a1
的位置被调用。它打印出"b1"
并返回a1
不变。由于a1
保持不变,b1
在后续a1
调用中不起任何作用。
因此,以下评论不太正确:
a1() # will print b1 a1
事实上,
a1()
仅打印"a1"
。 "b1"
由@b1
/ def a1():
打印。如果您更改代码并重新运行,则事件序列应该更加清晰:
def b1(fnc):
print "b1"
return fnc
@b1
def a1():
print "a1"
if __name__ == "__main__":
print 'in __main__'
a1()
a1()
最后,为了达到你想要的效果,装饰者需要返回一个不同的可调用对象:
def b1(fnc):
def decorated():
print "b1"
return fnc()
return decorated
@b1
def a1():
print "a1"
if __name__ == "__main__":
print 'in __main__'
a1()
a1()
在这里,很清楚谁在呼叫fnc()
。
答案 1 :(得分:1)
谁在致电
fnc
?
基本上,代码最后一行()
后面的a1
。
那是怎么回事?装饰器旨在改变函数的行为。
因此,当您装饰某些东西时,会根据装饰器返回的内容创建一个新函数。这意味着装饰器在定义a1
时运行一次。这是一个证明这一点的例子:
print 'def b1'
def b1(fnc):
print "b1"
return fnc
print 'def a1'
@b1
def a1():
print "a1"
if __name__ == "__main__":
print 'main'
a1() # will print b1 a1
这将打印:
def b1
def a1
b1
main
a1
如您所见,在执行b1
之前调用装饰器main
。
它返回一个分配给别名a1
的函数实例,它可以像任何其他函数实例一样使用。
这就是代码最后一行()
之后的“调用运算符”a1
。
答案 2 :(得分:0)
查看How to make a chain of function decorators?
的热门答案因为你会注意到装饰器定义实际上正在转换函数,并返回转换后的函数。这在装饰时执行一次(当应用@时)。在您给出的示例中,b1未定义转换,但仍会执行print语句。然后返回原始函数,因此a1不会被“重新定义”。然后b1装饰器的动作是对a1做任何事情。
答案 3 :(得分:0)
让我们在装饰前调用a1_prev
a1
函数,a1()
变成
b1(a1_prev)()
而且不仅b1(a1_prev)
,最后()
是那些拨打func
返回的b1
的人。