在不改变被装饰对象原代码和调用方式的情况下给被装饰对象添加新的功能
并不是一门新的技术,而是由函数参数、名称空间、函数名多种用法、闭包函数组合成到一起的结果
对修改封闭,对扩展开。简单来说就是对修改原函数体代码是不行的,但是扩展新的功能是可以的
import time 倒入时间模块
print(time.time()) 时间戳(秒数):当前距离1970年1月1日0时0分0秒所经历的秒数
start_time = time.time() 定义一个开始时间
end_time = time.time() 定义一个结束时间
time.sleep(3) 让程序睡眠三秒钟在运行
==========================简易版本=============================
import time
def demo():
time.sleep(2)
print('hello demo')
#装饰器定义:在不改变代码的功能及调用方式的前提下,添加新的功能
'''使用闭包函数来做装饰器'''
'''
闭包函数需要函数体内函数,至少要有2层,
并且需要内层函数使用外层函数的名称空间中的名字
'''
def outer(xxx): # 外层函数 这里加了一个形参那么下面就需要一个实参
'''本质outer括号里面的就是被装饰函数的函数名'''
def inner(): # 内层函数
print('这里是函数调用前可以添加的功能') #这个是备注注释
start_time = time.time() #定义一个开始时间
xxx()
print('这里是函数调用后可以添加的功能') #这个也是备注注释
end_time = time.time() #定义一个结束时间
print('循环所消耗的时间>>>>:%s' % (end_time - start_time))
return inner # 闭包函数外层需要返回内层函数的函数名
'''这里outer括号内的实参用到了需要执行被装饰函数的函数名'''
'''这里也没有做好掩饰,没有把res换成上面被装饰的函数名'''
res = outer(demo) # 这里res是outer的返回值 返回inner函数的函数名
res() # 这样就相当于inner()
'''这个就是最基础版本的,但是还不够完善的装饰器,并且样子还没做好'''
==========================进阶版本=============================
'''完善装饰器,让他能够执行带参数、带返回值的被装饰对象'''
'''
因为要执行的被装饰对象,可能会涉及到多参数,
也有可能是单参数的,所以我们就得用到可变长参数
避免出现重复修改
'''
*args(接纳多余的位置参数) **kwargs(接纳多余的关键字参数)
def index(name):
time.sleep(2)
print('I AM KING!')
return 'only'
def index1():
time.sleep(1)
print('hello world')
return 'good night world'
def outer(xxx): # 这里的形参是为了接收被装饰函数的函数名
def inner(*args,**kwargs):
print('执行调用函数前,可以添加的功能')
start_time = time.time()
rel = xxx(*args, **kwargs) # 这里就是
print('执行调用函数后,可以添加的功能')
end_time = time.time()
print('循环所消耗的时间>>>>:%s' %(end_time - start_time))
return rel
return inner
'''index就是需要随意调用的一个函数'''
index = outer(index) # outer() 会直接返回值inner 而inner是内层函数的函数名
res1 = index('jason') # 这里就是相当于inner()因为是用
print(res1)
index1=outer(index1)
res = index1()
print(res)
'''
这里就已经完成了装饰器的制作了,支持了带参数和带返回值的,
不管是多参数的还是别的
'''
==========================最终版本=============================
'''最后可以在优化一下重复出现调用更改装饰器名字赋值给一个变量的步骤'''
@outer #这个是装饰器语法糖。用于把被装饰对象名字当成参数直接传递给装饰器
def ankn():
time.sleep(2)
print('form Golden Township')
return 'value'
res = ankn()#直接把函数ankn当成参数传给装饰器后赋值给res变量名
print(res)
万能模版
def outer(xxx):#这个xxx形参仅仅是为了让后面正在被装饰的对象名字放在实参里面
def inner(*args,**kwargs):#为了适应多参数、单参数等设置的可变长参数
print('调用函数前可以添加的功能')
rel = xxx(*args,**kwargs)#这里是被装饰对象把它赋值给rel变量名
print('调用函数后可以添加的功能')
return rel # 返回inner函数的返回值 rel也就是相当于被装饰对象
return inner
--------------------------------------------
'新建一个时间模块'
import time
def get_time():
time.sleep(3) # 使函数调用后睡眠3秒在运行
print('hello world')
return 'good evening world'
get_time()
res = get_time()
print(res)
'在以上代码基础上在拓展一下,给它加一个登录验证后再运用功能'
def outer(xxx):
def inner(*args,**kwargs):
print('调用函数前可以添加的功能')
name = input('请输入name>>>>:').strip()
password = input('请输入password>>>>:').strip()
if name == 'chen' and password == '123':
rel = xxx(*args,**kwargs)
print('调用函数后可以添加的功能')
return rel
else:
print('别tm瞎搞')
return '....'
return inner
@outer # 加上语法糖后即可使它无需再写重复步骤
def get_time():
time.sleep(3)
print('hello world')
return 'Good Night World'
res = get_time()
print(res)
def outer(xxx):
def inner(*args,**kwargs):
print('执行被装饰对象之前可以做的额外操作')
rel=xxx(*args,**kwargs)
print('执行被装饰对象之后可以做的额外操作')
return rel
return inner
'语法糖会自动将下面紧挨着的函数名当做第一个参数自动传给@函数调用'
@outer
def demo():
print('hello world')
return 'good night world'
res = demo()
print(res)
实现原理:基于@语法和函数闭包,将原函数封装在闭包中,然后将函数赋值为一个新的函数(内层函数),执行函数时再在内层函数中执行闭包中的原函数。
实现效果:可以在不改变原函数内部代码 和 调用方式的前提下,实现在函数执行和执行扩展功能。
- 适用场景:装饰器在很多场景中非常有用,例如:
- 日志记录: 可以使用装饰器来记录函数的调用信息,如时间、参数等,以便调试或分析程序行为。
- 权限控制: 可以使用装饰器来验证用户是否有权限执行特定的操作,例如检查用户是否登录。
- 性能测试: 可以使用装饰器来测量函数的执行时间,以便优化代码性能。
缓存: 可以使用装饰器来缓存函数的返回值,以避免重复计算。