1、什么是装饰器
本质上增强函数或类的功能的一个函数;
通俗来讲,装饰器可以让一个Python函数拥有原本没有的功能,可以通过装饰器,变的强大漂亮。
【比如孙悟空,通过炼丹炉、龙宫、拜师而获得火眼金睛、金箍棒、七十二变,而变得很厉害;但它始终是猴子(函数本身)】
装饰器的几点属性:
实质:是一个函数
参数:是你要装饰的函数名(并非函数调用)
返回:是装饰完的函数名(并非函数调用)
作用:为已经存在的对象添加额外的功能
特点:不需要对对象做任何的代码上的变动
python中装饰器是随着程序的加载运行而自动加载的,跟调不调用方法没有关系.所以只要是装饰器内部函数以外的部分都会自动加载执行,不用调用。
2、为何引入装饰器
实例一:
一个简单的函数,增加其他属性,但不影响原代码
#孙悟空吃桃子
def sun():
print('eat peach')
sun()
# 想增加一个sun可以有火眼金睛,不破坏原代码基础上
def lian_dan(func):
def change(*args,**kwargs):
print("火眼金睛")
return func(*args,**kwargs)
return change
@lian_dan
# 引用装饰器(把下面的孙放进炼丹炉里,并把新的复制给下方函数)
def sun():
print('eat peach')
sun()
#结果:
火眼金睛
eat peach
-----------不使用装饰器----------
def sun():
print('eat peach')
new_sun = lian_dan(sun()) #放入材料,原来孙悟空将方案给新的孙悟空
sun() #执行炼丹程序,新孙悟空出世
实例二:
不影响原代码基础上,增加权限
def play():
print('开始播放"孙悟空')
play()
userAge = 50
def canYou(func):
def decorator(*args,**kwargs):
# 加权限认证
if userAge > 1 and userAge < 10:
return func(*args,**kwargs)
print('your age is not right')
return decorator
@canYou
def play():
print('开始播放"孙悟空')
play()
# 结果:
your age is not right
实例三:
一次性在一个函数上用多个装饰器,代码执行顺序,从内到外
def lian_dan(func):
def change(*args,**kwargs):
print('火眼金睛')
return func(*args,**kwargs)
return change
def long(func):
def hi(*args,**kwargs):
print('金箍棒')
return func(*args,**kwargs)
return hi
def baishi(func):
def teach(*args,**kwargs):
print("七十二变")
return func(*args,**kwargs)
return teach
@baishi
@long
@lian_dan
def sun():
print('eat peach')
sun()
#结果:
七十二变
金箍棒
火眼金睛
eat peach
# 代码执行顺序,从内到外
3、装饰器可以解决哪些实际问题
实际应用:用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。
比如,需要计算两数相加的时间,两数相减的时间
# 函数
import time
def add(a,b):
start_time = time.time()
res = a+b
exec_time = time.time() - start_time
return res
使用装饰器
装饰器函数的外部函数传入我要装饰的函数名字,返回经过装饰后函数的名字;内层函数(闭包)负责修饰被修饰函数
import time
# 定义装饰器
def time_calc(func):
def wrapper(*args, **kargs):
# 可以自定义传入的参数
print(func.__name__)
start_time = time.time()
f = func(*args, **kargs)
exec_time = time.time() - start_time
# 返回传入的方法名参数的调用
return f
# 返回内层函数的函数名
return wrapper
# 使用装饰器
@time_calc
def add(a,b):
return a+b
@time_calc
def sub(a,b):
return a-b
add(1,3)
sub(2,9)
运行结果
4、装饰器背后原理
在上面代码中:
1、func是我要装饰器的函数,我想用装饰器显示func函数运行的时间;
2、@decorator这个语法相当于 执行 func = decorator(func),为func函数装饰并返回;
3、装饰器函数 - decorator,该函数的传入参数是func (被装饰函数),返回参数是内层函数;
4、这里的内层函数-wrapper,其实就相当于闭包函数,它起到装饰给定函数的作用,wrapper参数为args, kwargs。args表示的参数以列表的形式传入;kwargs表示的参数以字典的形式传入
def wrapper(*args,**kwargs):
print("args:", end= ' ')
print(args)
print("kwargs:", end=' ')
print(kwargs)
wrapper(["hi"],123,k = 110,p = 112)
# 结果:
args: (['hi'], 123)
kwargs: {'k': 110, 'p': 112}
5、@符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作
如没有使用@time_calc时,调用时,需要加上
tic = time_calc(sub)
6、如果有其他的类似函数,可以继续调用装饰器来修饰函数,而不用重复修改函数或增加新的封装;
归因于 python的函数可像普通对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可作为返回值,可被定义在另外一个函数内
最后,想弄懂装饰器,可先点击学习下之前讲解的 4.闭包
关于装饰器,还有两篇进行讲解,关注我,查看系列文章,完全搞定它!
网友评论