import time
def decorator(func):
def wrapper():
print(time.time())
func()
return wrapper()
@decorator
def f1():
print("This is a function")
f1()
今天学习python的装饰器功能
但是我在执行上面的代码是就会报错,教程中没有任何问题。
然后就去网上查资料,发下了下面这张帖子,说是在调用被装饰的方法时不需要加括号,然后我就很不理解,不加括号不应该是调用对象吗,加了括号才是执行方法啊。(看帖子中的评论,应该和版本有关,我的是3.6)
参考链接:https://blog.csdn.net/wth_97/article/details/82347803
然后又去查原因,发现了这篇帖子,我怀疑是不是被装饰后就不是一个方法了,没办法调用了
参考链接:https://www.cnblogs.com/wangeraaa/p/10236180.html
好吧,既然这样就输出一下他的类型
import time
def decorator(func):
def wrapper():
print(time.time())
func()
return wrapper()
@decorator
def f1():
print("This is a function")
print(type(f1))
代码改动不大,输出结果如下
1588937731.6673582
This is a function
<class 'NoneType'>
输出的类型为 NoneType,而且f1方法也执行了
继续测试,我把print(type(f1))方法删除了,执行一遍
1588937875.9700713
This is a function
没有调用,依然执行了。纳尼???
得出一个结论,装饰器方法会自动执行,
三秒后我想到了另一个结论,被装饰的f1无法被调用,因为只输出了一遍结果,是自动执行的那次调用,我下面的那次调用无效
好吧继续折腾~~~
我看到很多资料都是将f1方法传参,我也传参
def decorator(func):
def wrapper(name):
print(time.time())
func(name)
return wrapper()
@decorator
def f1(name):
print(name)
print("This is a function")
输出报错了
wrapper() missing 1 required positional argument: 'name'
少参数。。。。
好吧再折腾
对比网上的代码,教程视频的代码,我发现原因了,我写错了。。。。return wrapper不应该加个括号,而是直接返回wrapper。
该代码,结果,把括号去掉
import time
def decorator(func):
def wrapper(name):
print(time.time())
func(name)
return wrapper
@decorator
def f1(name):
print(name)
print("This is a function")
f1('李博')
f1('李博')
输出如下
1588939093.2899694
李博
This is a function
1588939093.2899694
李博
This is a functionProcess finished with exit code 0
哎,发现自己真的蠢,前面口口声声的说,带括号是执行函数不带括号是调用对象,这里肯定是要return wrapper对象的,而不是要这个函数的返回结果啊。之前说到的自动执行时这里return时执行的。哎
好吧,是我写错代码了,这次总结到这里了。。。。
等等,还有一件事~~~
为什么是返回一个函数对象,装饰器本质就是执行装饰器的代码块,然后调用参数传进来的函数,这里又返回了一个函数对象,啊,狸猫换太子
编写代码 我输出了f1对象,print(f1)
<function decorator.<locals>.wrapper at 0x000001F2351F1A60>
这里可以看导 decorator. 和 wrapper 我们并没有看到f1
好吧,还是有一丝怀疑,我们输出的明确一点 print(f1.__name__)
wrapper
明白了,装饰器就是这个原理啊,一个语法糖而已
也算是因祸得福了,教程中和其他的文章中都没看到这个知识点。自己也算是摸索出来了。
python学了很久了,有时候学着学着就想起来javascript语言,越来越庆幸自己学过javascript了,有了javascript学起python方便了不少,比如说闭包,和javascript很相似。
扩展一下,来个多装饰器的版本
import time
def decorator(func):
def wrapper():
print('装饰器1')
print(func.__name__)
func()
return wrapper
def decorator2(func):
def wrapper2():
print('装饰器2')
print(func.__name__)
func()
return wrapper2
@decorator2
@decorator
def f1():
print("This is a function")
f1()
猜猜输出结果是什么,我当时猜错了。。。我把执行顺序猜错了
装饰器2
wrapper
装饰器1
f1
This is a function
装饰器运行顺序是自下向上,可以看输出类型,装饰器2输出的对象名称是wapper,可以知道在此之前就被装饰器1掉包过了
执行顺序是自上向下,这个简单了,看输出顺序就好了