Python闭包函数-装饰器

闭包函数(重要知识点)

# 闭包函数的两大特征
      1.闭:定义在函数内部的函数
      2.包:内部函数使用了外层函数名称空间中的名字
    def outer():
        x = 999
        def inner():
            print('from outer>>>inner', x)
        return inner
    x = 666
    res = outer()
    res()

闭包函数实际应用

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

  # 函数体传参的方式2:闭包
   def outer():
       username = 'jason'
       def index():
           print(username)  # 永远使用的都是jason
       return index
   res = outer()
    def outer(username):
         username = 'jason'
    def index():
        print(username)  # 永远使用的都是jason
    return index
res = outer('kevin')  # 形参username与值kevin临时绑定 >>>:outer局部名称空间中
res()
res1 = outer('jason')  # 形参username与值kevin临时绑定 >>>: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)  # 两个时间戳的差值就是函数的执行时间

  '''
    1.思考:如果在很多地方都需要调用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()
          func_name(*args, **kwargs)
          end_time = time.time()
          print(end_time - start_time)
      return get_time

完整版装饰器

# 解决的是返回值问题
  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_name):
    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 wraps
  def outer(func_name):
      @wraps(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')

   help(home)  # help可以查看指定函数的注释信息
   help(len)
   index()  # 目前的以假乱真 有瑕疵
   print(index)
   help(home)
   help(index)
   print(home)
   print(index)
  home()
  index()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lamb!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值