装饰器语法糖运用

装饰器语法糖运用

  • 前言:函数名是一个特性的变量,可以作为容器的元素,也可以作为函数的参数,也可以当做返回值。

  • 闭包定义:

    • 内层函数对外层函数(非全局)变量的引用,这个内层函数就可以成为闭包

    • 在Python中我们用__closure__来检查函数是否是闭包

    • def func1():
          name = '张三'
      
          def func2():
              print(name)  # 能够访问到外层作用域的变量
          func2()
          print(func2.__closure__)  # (<cell at 0x1036c7438: str object at 0x10389d088>,)
      
      func1()
      print(func1.__closure__)  # None
      
  • 装饰器

    • 前言:软件设计原则:开闭原则,又称开放封闭原则

      • 指对扩展代码的功能是开放的,但对修改源代码是封闭的,
    • def create_people():
          print('女娲真厉害,捏个泥吹口气就成了人!')
      
      
      def a(func):
          def b():
              print('洒点水')
              func()
          return b
      
      ret = a(create_people)
      ret()
      
    • 通过装饰器语法等同于

    • def a(func):
          def b():
              print('洒点水')
              func()
          return b
      
      
      @a  # 装饰器语法糖的作用就是上述函数ret()
      def create_people():
          print('女娲真厉害,捏个泥吹口气就成了人!')
      
      create_people()
      
  • 装饰带返回值的函数,即return出被装饰函数的执行结果

    • def foo(func):  # 接收的参数是一个函数名
          def bar():  # 定义一个内层函数
              print("这里是新功能...")  # 新功能
              r = func()  # 在内存函数中拿到被装饰函数的结果
              return r  # 返回被装饰函数的执行结果
          return bar
      
      
      # 定义一个有返回值的函数
      @foo
      def f1():
          return '嘿嘿嘿'
      
      
      # 调用被装饰函数
      ret = f1()  # 调用被装饰函数并拿到结果
      print(ret)
      
  • 装饰带参数的函数

    • def func1(func):              # 接收的参数为一个函数名
          def inner(*args, **kwargs):     # 这里需要定义和被装饰函数相同的参数
              print("新功能")                # 新功能
              ret = func(*args, **kwargs)     #被装饰的函数和参数
              print("新功能")         
              return ret
          return inner
      
      # 定义一个需要俩个参数的函数
      @func1
      def func(a, b):
          return a + b
      
      
      ret = func(3, 5)
      print(ret)
      
  • 带参数的装饰器 即在装饰器外在写一层函数,从而使其带参数

    • def d(a=None):        # 定义一个外层函数,给装饰器传参数
          def func1(func):  # 接收的是一个函数名
              def inner(*args, **kwargs): # 被装饰的函数,和参数
                  if a:
                      print(f"欢迎来到{a}")   #添加新功能
                  else:
                      print("欢迎来到王者荣耀")  
                  func(*args, **kwargs)
              return inner
          return func1
      
      
      # @d("英雄联盟")
      # def func(st):
      #     print(st)
      # func("敌军还有三十秒到达战场")
                                    # 欢迎来到英雄联盟
                                    # 敌军还有三十秒到达战场
      
      @d()
      def func(st):
          print(st)
      func("敌军还有三十秒到达战场")
      # 欢迎来到王者荣耀
      # 敌军还有三十秒到达战场
      
  • 装饰器修复技术

    • 定义:被装饰的函数最终都会失去本来的__doc__等信息, Python给我们提供了一个修复被装饰函数的工具。

    • from functools import wraps    #导入
      print(f1.__doc__)
      print(f1.__name__)
      
  • 多个装饰器装饰同一函数

    • from functools import wraps
      
      def wrapper2(func):
          @wraps(func)
          def inner(*args, **kwargs):
              r = func(*args, **kwargs)
              return f"<2>{r}</2>"
          return inner
      
      def wrapper1(func):
          @wraps(func)
          def inner(*args, **kwargs):
              r = func(*args, **kwargs)
              return f"<1>{r}</1>"
          return inner
      
      @wrapper2
      @wrapper1
      def func(a):
          return a
      
      
      print(func("Hello World!!"))  #<2><1>Hello World!!</1></2>
      
    • def foo1(func):
          print("d1")
      
          def inner1():
              print("inner1")
              return "<i>{}</i>".format(func())
      
          return inner1
      
      
      def foo2(func):
          print("d2")
      
          def inner2():
              print("inner2")
              return "<b>{}</b>".format(func())
      
          return inner2
      
      
      @foo1
      @foo2
      def f1():
          return "Hello Andy"
      
      # f1 = foo2(f1)  ==> print("d2") ==> f1 = inner2
      # f1 = foo1(f1)  ==> print("d1") ==> f1 = foo1(inner2) ==> inner1
      
      ret = f1()  # 调用f1() ==> inner1()  ==> <i>inner2()</i>  ==> <i><b>inner1()</b></i> ==> <i><b>Hello Andy</b></i>
      print(ret)
      
  • 类装饰器

    • class D(object):
          def __init__(self, a=None):
              self.a = a
              self.mode = "装饰"
      
          def __call__(self, *args, **kwargs):
              if self.mode == "装饰":
                  self.func = args[0]  # 默认第一个参数是被装饰的函数
                  self.mode = "调用"
                  return self
              # 当self.mode == "调用"时,执行下面的代码(也就是调用使用类装饰的函数时执行)
              if self.a:
                  print("欢迎来到{}页面。".format(self.a))
              else:
                  print("欢迎来到首页。")
              self.func(*args, **kwargs)
      
      
      @D()
      def index(name):
          print("Hello {}.".format(name))
      
      
      @D("电影")
      def movie(name):
          print("Hello {}.".format(name))
      
      if __name__ == '__main__':
          index('张三')
          movie('张三')
      
  • 装饰类

    • # 定义一个类装饰器
      class D(object):
          def __call__(self, cls):
              class Inner(cls):
                  # 重写被装饰类的f方法
                  def f(self):
                      print('Hello 张三.')
              return Inner
      
      
      @D()
      class C(object):  # 被装饰的类
          # 有一个实例方法
          def f(self):
              print("Hello world.")
      
      
      if __name__ == '__main__':
          c = C()
          c.f()
      
posted @ 2018-10-31 23:18  云丛  阅读(135)  评论(0编辑  收藏  举报