装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。
它常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。
装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
首先我们看一个简单的例子:
def info():
print('hello')
我们实现了一个简单的函数:
- 若此时,我们有了一个新的需求:打印hello并且打印日志
- 那么可能大家都会想到,我添加一行打印日志的代码不就行了吗?
def info():
print('hello')
print('*******log1*******')
问题:
- 假如你就几十个函数都需要添加日志,那么你就必须把每个日志都找到,然后一行一行地添加代码
- 这样就会造成大量的重复代码,我们会不会在不动原函数的前提下实现我们的功能?
开放封闭原则:
对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。
# 这时可能有人想到了,我再创建个函数然后调用这个函数就可以实现,而且减少了代码重复
def info():
print('hello')
def logger(func):
func()
print('******logger******')
info=logger(info)
相当于我们之前是使用info()函数实现打印,现在又要使用logger()函数实现,若是别人不知道logger这个函数,只知道有info这个函数,他只想调用info这个函数
装饰器就要登场了
def info():
print('hello')
def logger(func):
def inner(): #装饰后的代码(闭包)
func()
print('******logger******')
return inner
'''
不难理解,inner这个函数就是装饰器函数,也是一个闭包,此时我们调用logger这个函数,返回了inner
我们再用info=logger(info)=inner,然后再使用info()就实现了扩展
'''
info=logger(info)
info()
# 还有一个问题,就是需要打印日志的函数很多,我们每次都要写
func=logger(func)
func()
这样也会很麻烦,还有没有更简便的方式,其实,python为我们提供了一个更简单的方式,使用(@装饰器函数)即可
- 但是装饰器函数必须写在你要使用的函数之前,否则就找不到你的装饰器函数
def logger(func):
def inner():
print('******logger******')
func()
return inner
@logger #这里的@logger就相当于info=logger(info)
def info():
print('hello')
info()
@logger
def bar():
print('GoodMorning!')
** 扩展:若我们的函数是个带参函数且有返回值,那么我们装饰器部分的形参可以使用*args和**kwargs
def result(func):
def inner(*args,**kwargs):
print('******logger*******')
return func(*args)
#我们的函数存在返回值,若想的到返回值,就必须将该函数返回至上一层,一层一层传递,就可以最终得到原函数的返回值
return inner
@result
def add(*args): #一个加法运算的函数
num=0
for i in args:
num+=i
print(num)
return num
print(add(1,2,3)) #最终得到原函数的返回值6