zoukankan      html  css  js  c++  java
  • python 闭包 装饰器

    闭包

    1. 什么是闭包

    • 在 python 中创建一个闭包一般有3个要求:
      • (1)闭包函数必须有内嵌函数
      • (2)内嵌函数必须要引用外层函数的变量
      • (3)闭包函数返回内嵌函数的地址(函数名称)
    • 作用:可以在不修改目标源码的前提下,加功能
    • 注意:闭包函数中的变量的生命周期得到延长

    2. 创建一个闭包函数

    def funcOut():
        name = 'Jery'
            
        def funcIn():
            # format的简写方式
            print(f"姓名 = {name}")
        return funcIn
        
    f = funcOut()
    f()
    

     运行结果:

    姓名 = Jery
    

      

    3. 判断是否为闭包函数

    • 闭包函数相对与普通函数会多出一个__closure__的属性,里面定义了一个元组用于存放所有的cell对象,每个cell对象保存了这个闭包中所有的外部变量。
    • funcIn.__closure__:返回None,则不是闭包函数
    • 如:
      def funcOut():
          name = 'Jery'
          def funcIn():
              print(f"姓名 = {name}")
          print(funcIn.__closure__)
          print(funcIn.__closure__[0].cell_contents)  # 第一个外部变量
          return funcIn
      
      f = funcOut()
      f()
      

      运行结果

      (<cell at 0x000000000272F8B8: str object at 0x00000000026A08B8>,)
      Jery
      姓名 = Jery
      

      装饰器

      1. 本质及作用

      • 装饰器的本质
        • 闭包函数
      • 装饰器的作用:
        • 在不修改原函数及其调用方式的情况下对原函数功能进行扩展

      2. 装饰器的使用

    • 需求:为现有功能fun1增加日志功能
      • 传统方案解决 —— 使用闭包
         def writeLog(fn):
              print("记录日志")
              print('访问方法:'+fn.__name__)
        
          def funcOut(func):
              def funcIn():
                  writeLog(func)
                  func()
              return funcIn
              
          def fun1():
              print("使用功能1")
              
          def fun2():
              print("使用功能2")
          
          fun1 = funcOut(fun1)
          # 装饰器(闭包)
          fun1()
        
      • 运行结果:

        记录日志
        访问方法:fun1
        使用功能1 
      • 使用装饰器(语法糖)解决 

          def writeLog(fn):
              print("记录日志")
              print('访问方法:'+fn.__name__)
          
          def funcOut(func):
              def funcIn():
                  writeLog(func)
                  func()
              return funcIn
          
          @funcOut
          def fun1():
              print("使用功能1")
          @funcOut
          def fun2():
              print("使用功能2")
          
          fun1()
          fun2()
        

        运行结果: 

        记录日志
        访问方法:fun1
        使用功能1
        记录日志
        访问方法:fun2
        使用功能2 

    3. 多个装饰器的使用

      • 如:

      • def war1(func):
            print("war 1")
        
            def inner(*args, **kwargs):
                print("======war1 start=====")
                func(*args, **kwargs)  # inner
                print("======war1 end=====")
                return inner
        
        def war2(func):
            print("war2")
        
            def inner(*args, **kwargs):
                print("======war2 start=====")
                func(*args, **kwargs)
                print("======war2 end=====")
            return inner
        
        @war1
        @war2
        def f():
            print("****self****")
        
        f()

      • 运行结果:
        war2
        war1
        ======war1 start=====
        ======war2 start=====
        ****self****
        ======war2 end=====
        ======war1 end=====  
      • 解释:
        (1)
        @war1
        @war2 之后相当于 --> f = war1(war2(f))
        其中war2(f)是一个函数,作为实参传递
        war2(f):
          print("======war2 start=====")
          print("****self****")
          print("======war2 end=====")
        
        war1(war2(f)):
          print("======war1 start=====")
          war2(f)
          print("======war1 end=====")
        (2)
        f() 相当于执行 --> war1(war2(f))() 

      4. 对有参数的函数进行装饰

      • def funcOut(fn):
            print("funcOut")
            def funcIn(aa, bb):
                print("funcIn1")
                fn(aa,bb)
                print("funcIn2")
            return funcIn
        
        @funcOut
        def test(a, b):
            print("a=%d,b=%d" % (a, b))
        # 装饰器装饰之后,这不是直接调用test方法,而是调用func_in方法
        test(1,2)
        

         结果

      • funcOut
        funcIn1
        a=1,b=2
        funcIn2

      5. 通用装饰器的使用

      • 一个装饰器可以装饰多个不同参数、不同返回值的函数
      • 如:
           def funcOut(fn):
                # 需要有参数,*args,**kwargs
                def funcIn(*args,**kwargs):
                    print("记录日志")
                    print('访问方法:'+fn.__name__)
                    # 需要有参数,*args,**kwargs
                    # 需要有返回值
                    return fn(*args,**kwargs)
                return funcIn
            
            # 待装饰函数1:无参数,无返回值
            @funcOut
            def test1():
                print("test1")
            test1()
            print("---------")
            # 待装饰函数2:无参数,有返回值
            @funcOut
            def test2():
                return "Hello"
            print(test2())
            print("---------")
            # 待装饰函数3:有参数,无返回值
            @funcOut
            def test3(a):
                print('a=%d'%a)
            test3(1)
            print("---------")
            # 待装饰函数3:有键值对参数,无返回值
            @funcOut
            def test4(**kwargs):
                print(kwargs)
            test4(a=1)
      • 结果
        记录日志
        访问方法:test1
        test1
        ---------
        记录日志
        访问方法:test2
        Hello
        ---------
        记录日志
        访问方法:test3
        a=1
        ---------
        记录日志
        访问方法:test3
        {'a': 1}

          

      

  • 相关阅读:
    pandas 和 matplotlib 的设置
    Django图(菜鸟教程)
    使用 pyperclip 实现复制粘贴
    Pycharm 使用 doctest 进行判断程序是否运行正常
    jieba 运行结果不显示 Building prefix dict from the default dictionary ...
    浮点数以 .0 结尾如何转换为整数
    IOS时间转时间戳出现Invalid Date的问题
    PHP小技巧
    CSS小技巧
    树状数组
  • 原文地址:https://www.cnblogs.com/songdanlee/p/11367571.html
Copyright © 2011-2022 走看看