注意装饰器的运行时机
Topic source你好,看了你的回复之后收益匪浅,但是还是有个疑惑,如果我在abc()这个函数里不是print而是return,那怎么在后面打出end-call呢?我尝试了很多方法都是先执行end-call才执行函数中的计算,最后都是begin-end-函数返回值这个结果,而不是begin-函数返回值-end
@看我头像啊哈哈 你只要先运行函数,再返回返回值就好了啊:
第一种方法:
...
result = func(*args, **kw):
print('End Call--')
return result
...
第二种方法:
...
return [func(*args, **kw), print('End Call--')][0]
...
上面两种方法是等效的,都是先执行func(*args, kw),然后打印 End Call, 然后再把func(args, *kw)的返回值返回出去
个人推荐第二种方法,比较符合python的精神:Pythonic
但是
def log(fun):
def wrapper(*args,**kw):
print("start")
return [fun(*args,**kw),print("end")][0]
return wrapper
@log
def test(x):
return x
print(test("a"))
运行的结果是: start end a 不能打出start a end
@看我头像啊哈哈 你要搞清楚当你执行test("a")的时候,这个test函数已经不是你定义的test函数,而是wrapper函数。所以,你想要在这个函数结束后再输出end,你必须再用一个装饰器去装饰·wrapper。 你现在的函数是 1.先执行print("start") 2.执行你的test(x),然而这里什么都没做,只return了一个x 3.执行完test(x)后,执行print('end') 4.整个函数,连同装饰器一起返回一个x = "a",并且执行print("a")
@看我头像啊哈哈
你对执行的时机理解的还是有些误解:
def log(fun):
def wrapper(*args,**kw):
print("start")
return [fun(*args,**kw),print("end")][0]
return wrapper
@log
def test(x):
return x
print(test("a"))
装饰器log作为test函数的装饰器,使得函数运行前后进行一些额外工作外,最终返回了函数的执行结果
@log
def test(x):
return x
添加了@log
,简而言之,可视为最终使test函数变成了这样:
def test(x):
print("start")
def test_raw(arg):
return arg
return [test_raw(x), print('end')][0]
所以你执行 print(test("a"))
,结果肯定是:
start
end
a
因为你这个 print
是包裹在函数外面的。所以运行时机肯定是在函数运行完之后。
@信勒个达
因为在函数执行之前,装饰器先运行了,并且最终返回了wrapers这个函数。
@log
这个语法糖,是直接把函数装进去,然后再返回装饰之后的函数。这个时机是不需要函数执行的。
所以参数打印出来的时机在执行函数前。
- 1
- 2
儒生脱尘
我写的这个包含了运行的具体时间和运行的时机:
运行结果:
实际上可以看出,在文件运行时,函数还未执行前,装饰器自己先运行了一阵。