开放封闭原则
用开放封闭这一对反义词组成的原则可能会让你感觉到很矛盾,其实不然,因为开放封闭是分开来讨论的。
你应该清楚我们所开发的一切软件都不可能完美无缺,其功能也会随着时间的退役不断上升至新的高度,但是一旦我们得源码一经推出便无法进行修改,此时想要对功能进行扩张便显得有些费力,于是,我们不得不想其他的办法。由此开放封闭原则便很好的解决了这一需求。
何谓开放封闭原则,即:
1、对扩展是开放的
我们很清楚,任何一个程序都无法在设计之初就已经想好了所有的功能并保证在未来不作任何修改。故我们必须允许代码扩展、添加新功能。
2、对修改是封闭的
现实生活中,我们所写的函数很有可能已经交付给其他人使用,如果此时对函数内部进行修改,或者修改函数的调用方式,很有可能会影响已经在使用该函数的客户。
接下来我们先简单了解一下装饰器。
“装饰器”,从字面上看指的是为已有的东西添加新的功能。我们即将接触的装饰器即是以功能为导向的一个函数,被装饰的对象也是一个函数。
装饰器进化之路
最简单的装饰器
import time def timer(func): start = time.time() func() print(time.time() - start) def func1(): print('in func1') def func2(): print('in func2') timer(func1) timer(func2)
这种方式虽然看上去可以使用,但是对于别人来说,还是改用了调用的方式。于是我们进行改进:让他人调用func1的时候依然能够实现调用timer方法的效果。
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') print(func2('aaaaaa'))
另外,我们还可以在装饰器上加一点东西进行完善,用于查看函数的一些信息
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__) #查看函数名的方法
现在我们来总结一下装饰器的主要功能和固定结构
装饰器的主要功能:
在不改变函数调用方式的基础上在函数的前、后添加功能。
装饰器的固定格式:
def timer(func): def inner(*args,**kwargs): '''执行函数之前要做的''' re = func(*args,**kwargs) '''执行函数之后要做的''' return re return inner
装饰器的固定格式--wraps版
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()
多个装饰器装饰同一个函数
有些时候,我们也会用到多个装饰器装饰同一个函数的情况。
def 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()