装饰器

 

 

今日内容概要

1.闭包函数

2.闭包函数的实际应用

3.装饰器简介(重点加难点)

4.简易版本装饰器

5.进阶版本装饰器

6.完整版本装饰器

7.装饰器模板(拷贝使用即可)

8.装饰器语法糖

9.装饰器修复技术

今日内容详细

闭包函数(重要)

# 闭包函数的两大特征
1.闭:定义在函数内部的函数
2.包:内部函数使用了外层函数名称空间中的名字

def outer():
   a = 999
   def inner():
       print('from outer>>>inner',a)
   return inner
a = 888
res = outer()
res()

闭包函数实际应用

# 闭包函数是给函数体传参的另外一种方式
# 函数体传参的方式
1. 形参
def index(user_name):
   print(user_name)
# 函数体代码需要什么就可以在形参中写什么
index('zhou')

2.闭包
def outer():
   user_name = 'zhou'
   def index():
       print(user_name) # 永远使用的都是zhou
   return index
res = outer()

def outer(user_name):
   # user_name = 'zhou'
   def index():
       print(user_name) # 永远使用的都是zhou
   return index
res = outer('chen') # 形参user_name与值chen临时绑定>>>:outer局部名称空间中
res()
res1 = outer('zhou') # 形参user_name与值zhou临时绑定>>>:outer局部名称空间中
res1()

装饰器简介

"""
装饰器并不是一个新的知识点 而是由前两天所有的函数知识点整合到一起的产物
    名称空间 函数名 闭包函数...
"""
装饰器的本质
   在不改变被装饰对象原有的‘调用方式’和‘内部代码’的情况下给被装饰对象添加新的功能
 
装饰器的原则: 对扩展开放 对修改封闭

import time
# print(time.time()) # 1647568920.168808
'''上述的数字是时间戳:1970年1月1日0时0分0秒距离刚刚代码运行间隔的秒数'''
# time.sleep(3)
# print('hello world')

# 需求:统一函数的执行时间
import time
def index():
   time.sleep(3)
   print('from index')
'''给index函数增加了一个统计执行时间的功能'''
start_time = time.time() # 函数执行之前获取一个时间戳
index()
end_time = time.time() # 函数执行之后获取一个时间戳
print(end_time - start_time) # 两个时间戳的差值就是函数的执行时间

 

 

 

简易版本装饰器

import time
def index():
   time.sleep(1)
   print('from index')
'''给index函数增加了一个统计执行时间的功能'''
start_time = time.time() # 函数执行之前获取一个时间戳
index()
end_time = time.time() # 函数执行之后获取一个时间戳
print(end_time - start_time) # 两个时间戳的差值就是函数的执行时间

思考:如果在很多地方都需要调用index,如何统计index执行时间
  >>> 在很多地方都需要执行统计index函数执行时间的代码
  >>> 在不同的地方需要执行相同的代码
  >>> 函数
   
直接通过传参的方式
 缺陷1:
   代码写死了 无法统计其他函数的执行时间
   能否解决?
     可以 将函数名通过形参的形式传入
 缺陷2:
   封装成函数之后 调用方式改变了 不符合装饰器原则
   能否解决?
     不可以
       
def get_time(func):
   start_time = time.time() # 函数执行之后获取一个时间戳
   func()
   end_time = time.time() # 函数执行之后获取一个时间戳
   print(end_time - start_time) # 两个时间戳的差值就是函数的执行时间
def home():
   time.sleep(3)
   print('from home')
get_time(index)
get_time(home)
'''
第一种直接给函数体传参的方式无法实现装饰器
只能采用第二种给函数体传参的方式试试看了
'''

 

 


import time
def index():
   time.sleep(1)
   print('from index')
def home():
   time.sleep(3)
   print('from home')
print(home)
def outer(func): # 真正的index被outer局部名称空间存储了
   def get_time():
       start_time = time.time() # 函数执行之前获取一个时间戳
       func() # 调用了真正的index函数
       end_time = time.time() # 函数执行之后获取一个时间戳
       print(end_time - start_time) # 两个时间戳的差值就是函数的执行时间
   return get_time
res = outer(index) # 左侧的res就是一个普通的变量名
res()
a = outer(index) # 左侧的a就是一个普通的变量名
a()
b = outer(index) # 左侧的b就是一个普通的变量名
b()
index = outer(index)
index() # 看似调用的是index 其实调用的谁是get_time
print(index) # 全局名称空间中的index指向的是get_time函数体代码
home = outer(home) # 狸猫换太子

 

进阶版本装饰器
# 解决的是参数问题
def outer(func_name):
   def get_time(*args,**kwargs):
       start_time = time.time()
       res = func_name(*args,**kwargs) # 执行真正的index函数
       end_time = time.time()
       print(end_time - start_time)
       # return '不要急躁' # 如何在此处返回真正index函数的返回值
       return res
   return get_time

 

 

 

装饰器模板(重要)

'''编写装饰器其实有一套固定的代码 不需要做任何理解'''

def outer(func_name): # func_name用于接收装饰的对象(函数)
   def inner(*args,**kwargs):
       print('执行被装饰函数之前 可以做的额外操作')
       res = func_name(*args,**kwargs) # 执行真正的被装饰函数
       print('执行被装饰函数之后 可以做的额外操作')
       return res # 返回真正函数的返回值
   return inner

 

 

 

装饰器语法糖

# 仅仅是让代码编写的更加好看,简洁

def outer(func_time):
   def inner(*args,**kwargs):
       print('执行函数之前的操作')
       res = func_name(*args,**kwargs)
       # 额外操作
       return res
   return inner

@outer # 等价于 index = outer(index)
def index(*args,**kwargs):
   print('from index')
index = outer(index) # 总感觉这一行代码有点low

@outer # 等价于 home = outer(home)
def home(*args,**kwargs):
   print('from home')
   
print(index)
print(home)

'''
语法糖内部原理
  1.使用的时候最好紧跟在被装饰对象的上方
  2.语法糖会自动将下面紧挨着的函数名传给@后面的函数调用
 
'''

装饰器修复技术

from functools import warps
def outer(func_name):
   @warps(func_name)
   def inner(*args,**kwargs):
       print('执行被装饰对象之前可以做的操作')
       res = func_name(*args,**kwargs)
       return res
   return inner
@outer
def index():
   print('from index')
@outer
def home():
   '''这是home函数的注释'''
   print('from home')
home()
index()

最终整理的装饰器模板

# 简易版装饰器

def outer(func_name):   #  1. 定义外部函数
            def inner():    #  3.定义内部函数
            start_time = time.time()    #  7. 获取函数运行前的时间戳
            func_name()    #  8. 调用函数,内部函数调用外部函数绑定的形参,由于第2步形参传值,func_name与index临时绑定到一起,且这里是先调用outer函数再赋值,所以func_name绑定的是上面的函数名index,即调用函数index()
            end_time = time.time()   #  9. 获取函数运行后的时间戳
            print(end_time - start_time)   #  输出函数运行前后时间戳的差值
      return inner    #  4. 把内部函数的函数名返回出去
index = outer(index)   #  2. 调用外部函数   #  5. 定义变量名index,让index指向outer的返回值
index()    #  6. 调用函数,由于index指向inner,所以index()等价于inner(),即调用函数inner()

 

 

 



 

posted @ 2022-03-19 10:40  顺溜_7  阅读(81)  评论(0编辑  收藏  举报