1. 为什么要使用装饰器
比如下面代码要增加一个打印时间的功能,可以通过对原函数进行更改,或者再增加一个函数完成。
eg:
import time
def f2():
print("This is f2")
增加一个打印时间的功能
a.直接更改原函数实现
def f2():
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
print("This is f2")
b.通过新增加一个函数实现
def print_now_time():
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
f2()
但是如果要是有很多个函数,那么就要对很多个函数重新改写,或者重新定义一个函数来实现。
那么有没有办法,在保持原有函数调用的方法不变,实现增加一个打印时间的功能。那么就引出了装饰器。
def deco1(func):
def inner():
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
return func()
return inner
@deco1
def f2():
print("This is f2")
f2()
通过定义装饰器,在不改变原有函数调用方法,实现了新的功能。这个是我理解的装饰器的作用。
2.装饰器执行的顺序
eg:
import time
def deco1(func):
print('装饰器开始运行了!')
def inner():
print('函数执行开始了!')
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
return func()
print('函数执行结束了!')
print('装饰器运行结束了!')
return inner
@deco1
def f2():
print("This is f2")
f2()
运行结果:
装饰器开始运行了!
装饰器运行结束了!
函数执行开始了!
2020-08-23 10:19:52
This is f2
函数执行结束了!
通过以上我们可以知道,装饰器在程序初始化的时候,就已经开始运行。但装饰器里面的函数是在程序开始执行的时候,才开始调用。
那么如果有多个装饰器,他们的执行顺序又是怎么样的呢?
eg:
import time
def deco1(func):
print('装饰器1开始运行了!')
def inner():
print('函数1执行开始了!')
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
time.sleep(3)
return func()
print('函数1执行结束了!')
print('装饰器1运行结束了!')
return inner
def deco2(func):
print('装饰器2开始运行了!')
def inner():
print('函数2执行开始了!')
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
time.sleep(2)
return func()
print('函数2执行结束了!')
print('装饰器2运行结束了!')
return inner
@deco1
@deco2
def f2():
print("This is f2")
运行结果:
装饰器2开始运行了!
装饰器2运行结束了!
装饰器1开始运行了!
装饰器1运行结束了!
函数1执行开始了!
2020-08-23 10:24:58
函数2执行开始了!
2020-08-23 10:25:01
This is f2
函数2执行结束了!
函数1执行结束了!
从上面我们可以看到,装饰器是从内向外开始初始化,装饰器内的程序是从外开始先内运行。
3.以上函数是未带参数,如果需要装饰的函数带参数,那么装饰器又是怎么样的呢?
eg:
import time
def dec3(func):
def inner(*args,**kwargs):
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
return func(*args,**kwargs)
return inner
@dec3
def f3(name):
print('Good morning',name)
f3('Jon')
输出结果:
2020-08-23 10:34:14
Good morning Jon
4. 函数可以带参数去执行了,那么装饰器是否可以带上参数呢?
eg:
import time
def judeg(times):
def dec4(func):
def inner(*args,**kwargs):
hour=time.localtime().tm_hour - times
if hour >=0:
print('现在距离{times}点已过{hour}小时'.format(times=times,hour=hour))
else:
print('现在距离{times}点还有{hour}小时'.format(times=times,hour=-hour))
return func(*args,**kwargs)
return inner
return dec4
@judeg(12)
def f4(name):
print("Hello",name)
f4('Mike')
运行结果:
现在距离12点还有1小时
Hello Mike
5. 类装饰器
eg:
class Foo:
def __init__(self,func):
self._func = func
def __call__(self):
print("装饰器开始运行!")
self._func()
print("装饰器运行结束!")
@Foo
def f1():
print('Hello')
f1()