了解闭包之前需要明白,全局变量与局部变量及作用域的了解。
闭包的作用:使用闭包 该函数 经常使用时减少内存的开销
闭包的要求:
def func(): b = 2 def func2(): return b
装饰器作用:在不改变函数调用的方式下,在函数的前后添加功能
装饰器的本质:闭包函数
装饰器的基本结构:
def wrapper(func): def inner(*args,**kwargs): """执行函数前""" ret = func(*args,**kwargs) """执行函数后""" return ret return inner
************************************************************
楔子
作为一个会写函数的python开发,我们从今天开始要去公司上班了。写了一个函数,就交给其他开发用了。
def func1():
print('in func1')
季度末,公司的领导要给大家发绩效奖金了,就提议对这段日子所有人开发的成果进行审核,审核的标准是什么呢?就是统计每个函数的执行时间。
这个时候你要怎么做呀?你一想,这好办,把函数一改:
def func1(): print('in func1')
你要做的就是,让你的同事依然调用func1,但是能实现调用timer方法的效果。
import time def timer(func): start = time.time() func() print(time.time() - start) def func1(): print('in func1') func1 =timer #要是能这样的就完美了。。。可惜报错 func1()
装饰器的形成过程
import time def func1(): print('in func1') def timer(func): def inner(): start = time.time() func() print(time.time() - start) return inner func1 = timer(func1) func1()
忙活了这么半天,终于初具规模了!现在已经基本上完美了,唯一碍眼的那句话就是还要在做一次赋值调用。。。
你觉得碍眼,python的开发者也觉得碍眼,所以就为我们提供了一句语法糖来解决这个问题!
import time def timer(func): def inner(): start = time.time() func() print(time.time() - start) return inner @timer #==> func1 = timer(func1) def func1(): print('in func1') func1()
到这里,我们可以简单的总结一下:
装饰器的本质:一个闭包函数
装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展
还有最后一个问题要解决,刚刚我们讨论的装饰器都是装饰不带参数的函数,现在要装饰一个带参数的函数怎么办呢?
def timer(func): def inner(a): start = time.time() func(a) print(time.time() - start) return inner @timer def func1(a): print(a) func1(1)
其实装饰带参的函数并不是什么难事,但假如你有两个函数,需要传递的参数不一样呢?
import time def timer(func): def inner(*args,**kwargs): start = time.time() re = func(*args,**kwargs) print(time.time() - start) return re return inner @timer #==> func1 = timer(func1) def func1(a,b): print('in func1') @timer #==> func2 = timer(func2) def func2(a): print('in func2 and get a:%s'%(a)) return 'fun2 over' func1('aaaaaa','bbbbbb') print(func2('aaaaaa'))
现在参数的问题已经完美的解决了,可是如果你的函数是有返回值的呢?
import time def timer(func): def inner(*args,**kwargs): start = time.time() re = func(*args,**kwargs) print(time.time() - start) return re return inner @timer #==> func2 = timer(func2) def func2(a): print('in func2 and get a:%s'%(a)) return 'fun2 over' func2('aaaaaa','bbbbbb') print(func2('aaaaaa'))
刚刚那个装饰器已经非常完美了,但是正常我们情况下查看函数的一些信息的方法在此处都会失效
def index(): '''这是一个主页信息''' print('from index') print(index.__doc__) #查看函数注释的方法 print(index.__name__) #查看函数名的方法
为了不让他们失效,我们还要在装饰器上加上一点来完善它:
from functools import wraps def deco(func): @wraps(func) #加在最内层函数正上方 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper @deco def index(): '''哈哈哈哈''' print('from index') print(index.__doc__) print(index.__name__)
开放封闭原则
1.对扩展是开放的
为什么要对扩展开放呢?
我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。
2.对修改是封闭的
就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。装饰器完美的遵循了这个开放封闭原则。
装饰器的主要功能和装饰器的固定结构
装饰器的主要功能:
在不改变函数调用方式的基础上在函数的前、后添加功能。
装饰器的固定格式:
def timer(func): def inner(*args,**kwargs): '''执行函数之前要做的''' re = func(*args,**kwargs) '''执行函数之后要做的''' return re return inner
from functools import wraps def deco(func): @wraps(func) #加在最内层函数正上方 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper
带参数的装饰器
假如你有成千上万个函数使用了一个装饰器,现在你想把这些装饰器都取消掉,你要怎么做?
一个一个的取消掉? 没日没夜忙活3天。。。
过两天你领导想通了,再让你加上。。
def outer(flag): def timer(func): def inner(*args,**kwargs): if flag: print('''执行函数之前要做的''') re = func(*args,**kwargs) if flag: print('''执行函数之后要做的''') return re return inner return timer @outer(False) def func(): print(111) func()
执行流程分析
F = True #step 1 装饰器的开关变量 def outer(flag): #step 2 def wrapper(func): #step 4 def inner(*args,**kwargs): #stpe 6 if flag: #step 9 print('before') #step 10 ret = func(*args,**kwargs) #step 11 执行原函数 print('after') #step13 else: ret = func(*args,**kwargs) print('123') return ret #step 14 return inner #step 7 return wrapper #step 5 @outer(F) #先执行step 3 :outer(True)这个函数,然后step 6:@wrapper #此处把开关参数传递给装饰器函数 def hahaha(): pass #step 12 hahaha() # step 8 相当于inner()
多个装饰器装饰同一个函数
有些时候,我们也会用到多个装饰器装饰同一个函数的情况。
ef wrapper1(func): def inner(): print('wrapper1 ,before func') func() print('wrapper1 ,after func') return inner def wrapper2(func): def inner(): print('wrapper2 ,before func') func() print('wrapper2 ,after func') return inner @wrapper2 @wrapper1 def f(): print('in f') f()