函数(三)


闭包函数

闭包,又称闭包函数或者闭合函数,其实和前面讲的嵌套函数类似,不同之处在于,闭包中外部函数返回的不是一个具体的值,而是一个函数。一般情况下,返回的函数会赋值给一个变量,这个变量可以在后面被继续执行调用。
    # 闭包函数的两大特征
      1.闭:定义在函数内部的函数
      2.包:内部函数使用了外层函数名称空间中的名字
     
    def outer():
        x = 999
        def inner():
            print('from outer>>>inner',x)
        return inner
    x = 666
    res = outer()
    res()  # 结果999 

闭包函数的实际应用

    '''闭包函数是给函数体传参的另外一种方式'''
     # 函数体传参的方式有形参 闭包
     # 方式1:形参
        def info(username)
            print(usernam)
        # 函数体需要什么参数在形参在写对应的就行
        info('张三')
      
      # 方式2:闭包
      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()

装饰器简介

装饰器是 Python 的一个重要基础部分。简单地说:他们是修改或实现其他函数的功能的函数(工具)。他们有助于让我们的代码更简短,也更能体现程序员的基础是否牢固(写的好的就是“装杯”)。大多数初学者不知道在哪儿使用它们,所以我将要分享下,哪些区域里装饰器可以让你的代码更简洁。
    """
    装饰器并不是一个新的知识点 而是由前两天所有的函数知识点整合到一起的产物
    	名称空间 函数名 闭包函数...
    """
    装饰器的本质
    	在不改变被装饰对象原有的'调用方式'和'内部代码'
      的情况下给被装饰对象添加新的功能
      
    装饰器的原则
    	对扩展开放
      对修改封闭

     # 时间戳
      import time  # 导入模块
      # print(time.time())  # 1647568920.168808
      '''上述的数字是时间戳:1970年1月1日0时0分0秒距离刚刚代码运行间隔的秒数'''
      
    import time  # 导入time模块
    def outer(func_name):
        def get_time(*args, **kwargs):      # 可变长参数
            start_time = time.time()   # time.time()为时间戳 函数体开始的时间戳
            res = func_name(*args, **kwargs)  # 执行真正的play函数
            end_time = time.time()  # 函数体运行结束后的时间戳
            print(end_time - start_time)  # 两个时间戳的差
            # 如何在此处返回真正index函数的返回值
            return res  #
        return get_time

简易版装饰器

    # 装饰器有参数的写法
    def fly():
        time.sleep(2)  # 停止2秒
        print('两秒真男人!!')
     
    import time  # 导入time模块
    def outer(func_name):
        def get_time(*args, **kwargs):      # 可变长参数
            start_time = time.time()   # time.time()为时间戳 函数体开始的时间戳
            func_name(*args, **kwargs)  # 执行真正的play函数
            end_time = time.time()  # 函数体运行结束后的时间戳
            print(end_time - start_time)  # 两个时间戳的差
        return get_time

    fly = outer(fly)  # 将函数作为实参赋值给
    fly()  # 相当于get_time()

完整版装饰器

    # 有返回值的写法
    def fly():
        time.sleep(2)  # 停止2秒
        print('两秒真男人!!')
        return '哈哈哈 伟啦'

    import time  # 导入time模块
    def outer(func_name):
        def get_time(*args, **kwargs):      # 可变长参数
            start_time = time.time()   # time.time()为时间戳 函数体开始的时间戳
            res = func_name(*args, **kwargs)  # 执行真正的play函数
            end_time = time.time()  # 函数体运行结束后的时间戳
            print(end_time - start_time)  # 两个时间戳的差
            # 如何在此处返回真正index函数的返回值
            return res  #
        return get_time


    fly = outer(fly)  # 将函数作为实参赋值给
    res = fly()
    print(res)  # 返回值: 哈哈哈 伟啦

装饰器模板

对于装饰器不太理解的其实不用太过于担心,只要记住下面的这个模板直接使用就行了
    '''编写装饰器其实有一套固定的代码 不需要做任何理解'''
    def outer(func_name):  # func_name用于接收被装饰的对象(函数)
        def inner(*args, **kwargs):
            print('执行被装饰函数之前 可以做的额外操作')
            res = func_name(*args, **kwargs)  # 执行真正的被装饰函数
            print('执行被装饰函数之后 可以做的额外操作')
            return res  # 返回真正函数的返回值
        return inner

装饰器语法糖

    '''可以使代码更整洁'''
    语法糖的用法就比较简单了,只要把编写好的装饰器
    在函数前或某些代码前一行写 @ + 装饰器名(装饰器的外层函数的函数名)
    import time  # 导入time模块
    def outer(func_name):
        def get_time(*args, **kwargs):      # 可变长参数
            start_time = time.time()   # time.time()为时间戳 函数体开始的时间戳
            res = func_name(*args, **kwargs)  # 执行真正的play函数
            end_time = time.time()  # 函数体运行结束后的时间戳
            print(end_time - start_time)  # 两个时间戳的差
            # 如何在此处返回真正index函数的返回值
            return res  # 
        return get_time

    # 装饰器语法糖
    @outer   # @ + 装饰器的外层函数的函数名 
    def play():  
        time.sleep(1)  # 停止一秒钟
        print('玩个寄吧游戏')
        return '你给我叫爸爸!'
    res = play()
    print(res)  # 打印返回值res 你给我叫爸爸!

装饰器修复技术

函数的装饰器修复技术,可以使被装饰的函数在增加了新的功能的前提下,不改变原来函数的函数名,还继续使用原函数的注释内容。让人很难发现是被装饰器修改过函数名。
    # 做到比真的还要真  但是本质其实没有变
    '''
       装饰器修复技术关键在于 from functools import wraps 
       和 @wraps() 的连用
    '''

    import time  # 导入time模块

    from functools import wraps
    def outer(func_name):
        @wraps(func_name)
        def get_time(*args, **kwargs):      # 可变长参数
            start_time = time.time()   # time.time()为时间戳 函数体开始的时间戳
            res = func_name(*args, **kwargs)  # 执行真正的play函数
            end_time = time.time()  # 函数体运行结束后的时间戳
            print(end_time - start_time)  # 两个时间戳的差
            # 如何在此处返回真正index函数的返回值
            return res  #
        return get_time
    # 装饰器语法糖
    @outer   # @ + 装饰器的外层函数的函数名
    def play():
        '''玩游戏不?'''
        time.sleep(1)
        print('玩个寄吧游戏')
        return '你给我叫爸爸!'
     # help可以查看指定函数的注释信息
    help(play)  # 没加前get_time(*args, **kwargs)  
                # 加了之后play()    玩游戏不?