Python 装饰器
装饰器
什么是装饰器
装饰器顾名思义就是一个有装饰功能的工具,那么装饰器又是用来装饰什么的?为什么要装饰这个东西?装饰的目的是什么呢?本文会一一作答让小弟一个一个说
开放封闭原则
谈及装饰器就要引申一个概念,那就是开放封闭原则,那么问题又来了 什么是开放封闭……好好好,直接说这个,开放封闭本来是两个对立的概念,也就是说是一对反义词,那么为什么要提出开放封闭原则呢?原因是在日常的开发工作中,一般最初上线的产品的功能是不尽完善的,就是说不够完美但已经能够支撑日常使用,其余的功能可以日后扩展,举例:N年前的QQ和现在的QQ(PS:虽然现在本人不怎么用了)。在后期扩展功能时,因为函数已经是写好的,而且存在大量调用,所以要直接去给函数增添新的功能显然不现实,所以我们只能新建函数去给原来的函数扩展功能(其实这就是一个装饰器啦)
那么开放封闭原则到底是什么? 答案是对源码封闭,对新功能开放
-
封闭原则:不要改变源代码
-
开放原则:能增加一些额外的功能
如果还有客观对开放封闭原则似知似解的话,没关系接着往下看,不影响您食用本文,因为Python装饰器本身就是对开放封闭原则完美的诠释
装饰器初识
不低调的说,装饰器就是一个函数,名字本来很高大上,但本质就是一个函数,装饰器函数的功能就是要装饰一个函数,在不改变被装饰函数的源代码及调用方式的前提下,为其增加额外的功能。是不是有点门道了,是不是觉得这玩意也没啥啦,真是优秀的同学。
代码show(技术博客不写代码干白话说出去丢人)
def warpper(f): #定义一个函数(装饰器),传入的参数是被修饰的函数的函数名
def inner(*args,**kwargs): #嵌套一个内存函数,这个函数主题才是执行被装饰函数源码的关键
'''这块可以加要在被装饰函数执行之前的操作哈'''
ret = f(*args,**kwargs) #这里的形参我会在下面说明
'''这里可以写被装饰函数之后的,兄嘚,别客气,想加啥方法加什么'''
return ret #这里的返回值如果我一会儿不忘的话也会在下面说明
return inner
@warpper #这个叫语法糖,嗯……可以吃(可能老外命名的时候就是这么想的),结构是@加函数名,作用下面会说明
def func():
print('我就是那个被装饰的函数')
简单说明
因为本人比较懒,所以原谅我直接把代码甩上去了,后面有注释,看懂了的大佬可以say goodbye啦,想打我的接着听我白话,那我就把备注再重复一遍,哈哈,你也看到了,装饰器用到了函数的嵌套(再具体点就是闭包,要问什么是闭包,百度吧,哈哈),首先外层函数接收到一个函数名,然后返回值是内层函数的函数名;再来内层函数可以接收参数,其中ret = f(*args,**kwargs)
有两个作用,一是执行了传入的函数,也就是执行了被修饰的函数,二是将返回值赋给了一个变量,此处要说明一下,对被修饰的函数功能的扩展要写在这里哦,最后 ret作为内层函数的返回值返回给函数执行者。
语法糖
@warpper
这东西和 func = wrapper(func)是一样的,也就是说最后三行代码可以这样写
#@warpper
def func():
print('我就是那个被装饰的函数')
func = wrapper(func) #注意奥,这玩意要写在被装饰函数的下边,语法糖才写上边
至于为什么要写着东西,或者为什么要用语法糖?请听下回分解~~~,收起你滴拳头,是这样,我刚开始的时候谈到了,装饰器是要在不改变源码和其调用方式的前提下给其增加新的功能,注意到了么 调用方式 嗯……没错就是调用方式,如果我不这样写那我是不是要wrapper(func)()
这样去调用啊,是不是有点绕了,但是我把wrapper(func)
赋值给了一个和被装饰函数同名的变量,那我此时要怎么调用,是不是就是func()
,这样就满足了开放封闭原则,完美!其实本质就是要把装饰器“伪装”成原函数,包括调用方式、参数、返回值,装就要装的像一点,对吧。
装饰带参数的装饰器
def wrapper(f):
def inner(*args,**kwargs):
f(*args,**kwargs)
return inner
@wrapper
def func(a,b):
print(a,b)
函数func中有两个形参a和b,说一下这两个参数在装饰器中的旅程,函数inner的万能参数接收到a和b打包,然后inner函数充当中间商将打包后的元组给了f,在f中打散又成了变量a和b,在装饰器时就不会影响传参了,这就是装饰带参数的函数
装饰有返回值的函数
def wrapper(f):
def inner():
ret = f()
return ret
return inner
@wrapper
def func():
return('我不管,我最帅')
哈哈,这段代码中有我的心声,你们都懂的,很简单,装饰有返回值的参数,在inner函数中将f()赋值给ret,这样ret就接收到了返回值,再将ret返回给inner(),以此来达到“模拟”被装饰函数的返回值,也可以说是通过这种方法来拿到被装饰函数的返回值。
第一篇正经写的文章,可能文章内容表达不尽如人意的正经哈,但初心是好的,就是分享知识,分享心得嘛,嗯,不管怎么说,我还是很欣慰的对自己,哈哈,能有人从中有收获就更perfect喽