decrator_装饰器

------------学习装饰器前需了解的三个知识点-----------------
1、高阶函数:函数作为变量使用及返回值,递归函数的使用
2、LEGB顺序作用域理解
3、闭包:可以这样理解
条件1:嵌套函数,一个函数f1内存在一个函数f2
条件2:f2引用了外部环境(包括f1的传参或定义)的变量,这时外部的变量和闭包的变量是被分割开来的
而百度中是这样的定义的:定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁
开放\封闭原则:
封闭:假设在一个功能正常的函数里去增加功能,不能修改原代码
开放:假设在一个功能正常的函数里去增加功能,能对原代码进行扩展

-----------------通过例子来理解---------------

假设在一个计算阶层函数(foo)里去增加计时show_time功能,
要求:1、不能修改原代码,遵守代码 开放封闭原则
2、保持原有的调用方式,不能改变阶层函数名称

第一步 ,我们先把准备函数写好
def foo():   # 原产品有的阶层功能
"""
原阶层函数功能
:param x:
:param y:
"""
return reduce(lambda x,y : x*y,range(1,6))
print(foo())# 基本的阶层计算结果

基于上述要求1,先可以扩展一个阶层加定时功能的新函数 如下

第二步,我们对foo函数进行加定时功能
def show_time(fun): 
"""
新增的计时功能
"""
start = time.time()
time.sleep(1)
fun()
end = time.time()
return "show_time:%s"%(end-start)
print(show_time(foo)) # 这样我们可以在计算阶层的同时,计算这个过程的时间,但是我们调用show_time就违背了要求2

第三步,要求二是不能改变新增的功能名称,即我们可以从foo = show_time(fun)这个方向去思考

而在赋值给foo变量后,print(foo())这样运行是有问题的,本身show_time(fun)就已经执行了计时函数,这这时在付给foo的同时再加个(),会导致类型错误

下面我们要怎么办? 必须要不能改变原有的调用方式下增加计时功能,即foo() ,下面可以让闭包出场了,

第四步,我们对show_time函数进行改造,把show_time内嵌在另一个函数内(我改了下名字函数名 show_time2)

def show_time(fun):
"""
利用闭包方法
"""
def show_time2():
start = time.time()
time.sleep(1)
fun()
end = time.time()
return "show_time:%s" % (end - start)
return show_time2 # 当外部调用时,直接返回定位到show_time2函数变量的内存
  # 注意:这里若显示:return "show",show_time2,(show_time函数的返回值加入字符串等其他内容,返回的就不是一个函数变量,而是元组,元组是不可被作为实参传递)

foo = show_time(fun)
print(foo()) 执行foo时我们就已经定位到了show_time2的内存地址,加上括号我们就运行了show_time2函数功能

后面官方为了简化,提高逼格档次,foo = show_time(fun) 可以等价于 @show_time ,所有装饰器模型就处理了

第五步:在需要使用被装饰器函数前面 加上 @装饰器函数即可

#decrator.py
def show_time(fun):
"""
利用闭包方法
"""
def show_time2():
start = time.time()
time.sleep(1)
fun()
end = time.time()
return "show_time:%s" % (end - start)
return show_time2

@show_time # foo = show_time(fun) 可以等价于 @show_time
def foo():   # 原产品有的阶层功能
"""
原阶层函数功能
:param x:
:param y:
"""
return reduce(lambda x,y : x*y,range(1,6))

if __name__ == '__main__':
print(foo())













posted @ 2021-01-24 20:08  樱花满地集  阅读(83)  评论(0)    收藏  举报