装饰器:本质上就是函数,功能室为其他函数添加附加功能
装饰器的原则:
1、不修改被修饰函数的源代码
2、不修改被修饰函数的调用方式
装饰器的知识储备:
装饰器 = 高阶函数+函数嵌套+闭包
一、高阶函数的定义:
1、函数接收的参数是一个函数名
2、函数的返回值是一个函数名
3、满足上述任意一个条件都称之为高阶函数
def foo():
print('你好啊')
def test(func):
print(func)
func()
test(foo)
在这里test是高阶函数.但是高阶函数不能满足装饰器,比如:
import time
def foo():
time.sleep(2)
print('你好啊')
def test(func):
print(func)
start_time = time.time()
func()
stop_time = time.time()
print('函数运行的时间是 %s' % (stop_time-start_time))
test(foo)
这里修改了函数的调用方式,所以违反了装饰器的规则,代表着如果以后如果其他人想使用foo就需要用调用函数的方法来使用foo,又违反了开放封闭原则
但是可以用给函数赋值的方法避开这里
def timer(func):
start_time = time.time()
func()#1、首先运行foo,睡2s打印你好
stop_time = time.time()
print('函数运行的时间是 %s' % (stop_time-start_time))#2、然后打印时间
return func
foo = timer(foo)
foo()#3、在这里已经运行了一边func,也就是foo,所以还会运行一遍
上面结果为:你好啊 时间 你好啊
二、函数的嵌套
函数的嵌套就是函数中再次定义一个函数,就是函数的嵌套
三、闭包
闭包可以理解成某个函数被当成对象返回时,夹带了外部的一个变量,就形成了一个闭包
三者结合,就成为了装饰器:
#装饰器的框架:
def timmer(func):#传入了一个东西
def wapper():
print(func)#wapper函数中没有func所以向上去取
func()#同理,也可以运行
return wapper
有了框架可以写一个计算运行时间的函数
import time
def test():
time.sleep(2)
print('test函数运行完毕')
如果在框架后让框架传入test,再运行,就可以绕过test函数对test函数进行操作
res = timmer(test)
res()
这时候把计算时间的代码块添加入内
def timmer(func):
def wapper():
start_time = time.time()#开始计时
func()运行test函数
stop_time = time.time()#结束计时
print('运行时间 %s' % (stop_time-start_time)#计算时间
return wapper
这里虽然没有改test的源代码,也没有改test的调用方式,但是对test进行了赋值,这个赋值如果代码量很大的话不可能全部做完,于是出现了语法糖
语法糖就是@符号
@timmer就相当于test = timmer(test)
要修饰什么函数就在哪个函数之前加一个@函数名
最后再运行该函数就可以了
#之前写好timmer函数
@timmer
def test():
time.sleep(2)
print('test函数运行完毕')
test()
如果这时候给test加上返回值如果直接在test函数后面加上return是不成功的,因为test传入timmer运行的是wapper,所以test就相当于是wapper,所以wapper的返回值就是test的返回值,但是如果就想return出test的返回值就需要给func一个值,然后再wapper中返回该值
def timmer(func):
def wapper():
start_time = time.time()#开始计时
res = func()运行test函数
stop_time = time.time()#结束计时
print('运行时间 %s' % (stop_time-start_time)#计算时间
return res#这里返回res就可以返test的返回值了
return wapper