美文网首页
day14 闭包和函数装饰器

day14 闭包和函数装饰器

作者: 代码小小白 | 来源:发表于2020-08-19 15:11 被阅读0次
    一、闭包

    1.概念:
    ① 闭包只存在于嵌套函数中
    ②和嵌套函数有区别,闭包必须存在内层函数对外层函数的非全局变量的引用
    2.闭包的用处:保证数据安全
    3.自由变量:

    def wrapper():
        a = 1
        def inner():
           print(a)
        return inner
     ret = wrapper() 
    # 是闭包,内层函数引用的了外层函数的变量a,
    #此时a称作自由变量,存在于一个独立的内存空间中,他不会随着函数的结束而消失
    
    def wrapper(a,b):
        def inner():
           print(a)
           print(b)
       return inner
    a = 2
    b = 3 
    ret = wrapper(a,b) # 也是闭包,内部函数inner引用了外部函数wrapper的变量a,b
    

    4.判断闭包:就是判断这个函数有没有自由变量

    ret = wrapper(a,b)
    print(ret.__code__.co_freevars)  # ('a', 'b')
    
    二、装饰器

    在不改变原函数的代码以及调用方式的前提下,为其增加新的功能。遵循开放封闭原则
    1.最基本的装饰器

    # 需求:计算一个函数的运行时间
    import time
    # 装饰器函数
    def wrapper(func):
      def inner():
        start_time = time.time() # 函数执行前的操作
        func()
        end_time = time.time() # 函数执行后的操作
        print(f'函数执行时间{end_time-start_time}')
      return inner
    
    # @wrapper 此处相当于  test_func = wrapper(test_func)
    @wrapper  
    def test_func():
      time.sleep(1)
      print("测试一些时间")
    
    test_func() 
    # 测试一些时间
    # 函数执行时间1.002511978149414
    

    2.被装饰函数带有返回值

    # 需求变了,test_func带有返回值
    import time
    # 装饰器函数
    def wrapper(func):
      def inner():
        start_time = time.time() # 函数执行前的操作
        ret = func() # 此处将函数的返回值赋给ret
        end_time = time.time() # 函数执行后的操作
        print(f'函数执行时间{end_time-start_time}')
        return ret # 将函数的返回值进行返回
      return inner
    
    # @wrapper 此处相当于  test_func = wrapper(test_func)
    @wrapper  
    def test_func():
      time.sleep(1)
      msg = "我是返回值"
      return msg
    
    a = test_func()
    print(a)
    # 函数执行时间1.004417896270752
    # 我是返回值
    

    3.被装饰函数带有参数

    # 需求又变了,test_func函数带有参数
    import time
    # 装饰器函数
    def wrapper(func):
      def inner(*args, **kwargs):
        # 函数定义阶段  *是函数的聚合,聚合成元祖 (x,y)
        start_time = time.time() # 函数执行前的操作
        ret = func(*args) # 函数执行阶段 *是打散 func(*args) -> func(*(x,y)) -> func(x,y)
        end_time = time.time() # 函数执行后的操作
        print(f'函数执行时间{end_time-start_time}')
        return ret
      return inner
    
    # @wrapper 此处相当于  test_func = wrapper(test_func)
    @wrapper  
    def test_func(x, y):
      time.sleep(1)
      msg = x + y
      return msg
    
    a = test_func(1, 2)
    print(a)
    # 函数执行时间1.0041322708129883
    # 3
    

    4.装饰器带有参数

    # 需求增加了,增加一个打印日志功能,通过一个参数控制是否需要打印
    import time
    
    # 装饰器函数
    def wrapper(func):
      def inner(*args, **kwargs):
        # 函数定义阶段  *是函数的聚合,聚合成元祖 (x,y)
        start_time = time.time() # 函数执行前的操作
        ret = func(*args) # 函数执行阶段 *是打散 func(*args) -> func(*(x,y)) -> func(x,y)
        end_time = time.time() # 函数执行后的操作
        print(f'函数执行时间{end_time-start_time}')
        return ret
      return inner
    
    # 带有参数的装饰器就是在原有装饰器的基础上在套一层
    def log(isneed):
        def wrapper(func):
            def inner(*args, **kwargs):
                ret = func(*args)
                if isneed:
                    print(f"函数名:{func.__name__}")
                else:
                    print("此时不需要打印")
                return ret
            return inner
        return wrapper
    
    #多装饰器,采取就近原则作为执行顺序
    @log(isneed=True)
    @wrapper  
    def test_func(x, y):
      time.sleep(1)
      msg = x + y
      return msg
    
    a = test_func(1, 2)
    print(a)
    # 函数执行时间1.004870891571045
    # 函数名:inner
    # 3
    

    5.@wraps
    上一个例子打印出来的函数名是inner,其实最初我们的函数名是test_func,为了避免这种情况,用到了@wraps装饰器

    import time
    from functools import wraps
    
    # 装饰器函数
    def wrapper(func):
        @wraps(func)
        def inner(*args, **kwargs):
        # 函数定义阶段  *是函数的聚合,聚合成元祖 (x,y)
            start_time = time.time() # 函数执行前的操作
            ret = func(*args) # 函数执行阶段 *是打散 func(*args) -> func(*(x,y)) -> func(x,y)
            end_time = time.time() # 函数执行后的操作
            print(f'函数执行时间{end_time-start_time}')
            return ret
        return inner
    
    def log(isneed):
        def wrapper(func):
            @wraps(func)
            def inner(*args, **kwargs):
                ret = func(*args)
                if isneed:
                    print(f"函数名:{func.__name__}")
                else:
                    print("此时不需要打印")
                return ret
            return inner
        return wrapper
    
    @log(isneed=True)
    @wrapper  
    def test_func(x, y):
      time.sleep(1)
      msg = x + y
      return msg
    
    a = test_func(1, 2)
    print(a) #此时打印出来的函数名为test_func, 需要注意的是,如果有多个装饰器,每一个都得用@wraps 否则打印出函数名还是inner
    

    相关文章

      网友评论

          本文标题:day14 闭包和函数装饰器

          本文链接:https://www.haomeiwen.com/subject/hqgkjktx.html