Python奇淫技巧第三弹之基本语法

1.函数装饰器2. 类装饰器3. super关键字

1.函数装饰器

  • 装饰器的定义:装饰器其实就是一个闭包,把一个函数当作参数传进去,然后返回一个替代版函数

  • 装饰器主要的分类:

    • 装饰器对无参数的函数进行装饰,对一个函数可以使用多个装饰器,执行顺序由内向外

      #定义函数:完成包裹数据
      def makeBold(fn):
          def wrapped():
              return "<b>" + fn() + "</b>"
          return wrapped
      ​
      #定义函数:完成包裹数据
      def makeItalic(fn):
          def wrapped():
              return "<i>" + fn() + "</i>"   #当有return时,适用于有返回和无返回的函数
          return wrapped
      @makeBold
      def test1():
          return "hello world - 1"
      ​
      @makeItalic
      def test2():
          return "hello world - 2"
      ​
      @makeBold
      @makeItalic
      def test3():
          return "hello world - 3"
      ​
      print(test1())  
      print(test2())
      print(test3())
      ​
      ######执行结果
      <b>hello world - 1</b>
      <i>hello world - 2</i>
      <b><i>hello world - 3</i></b>
      ​
      Process finished with exit code 0

       

    • 装饰器对有参数函数进行装饰

      #定义一个装饰器
      def deco(func):
          # 内部函数的参数必须和被装饰的函数保持一致
          def wrapper(a, b):
              print("获得被修饰函数的参数:a= %s,b= %s" % (a, b))
              return func(a, b)
          return wrapper
      ​
      #有参数的函数
      @deco
      def sum(a, b):
          return a+b
      ​
      print(sum(10, 20))
      ​
      ​
      ######执行结果
      获得被修饰函数的参数:a= 10,b= 20
      30
      ​
      Process finished with exit code 0
    • 装饰器对可变参数函数进行装饰

      #定义一个装饰器,装饰不定长参数函数
      def deco(func):
          def wrapper(*args,**kwargs):
              print("arguments args length : %d" % len(args))
              print("arguments kwargs length : %d" % len(kwargs))
              func(*args,**kwargs)
          return wrapper
      ​
      @deco
      def test1(a, b, c):
          print(a+b+c)
      ​
      @deco
      def test2(a, b):
          print(a+b)
      ​
      @deco
      def test3(*args,**kwargs):
          print(args)
          print(kwargs)
      ​
      ​
      print("*************")
      test1(10, 20, 30)
      print("*************")
      test2(10, 20)
      print("*************")
      test3(1, 2, 3, d=4, x=5)
      ​
      ​
      ######执行结果
      *************
      arguments args length : 3
      arguments kwargs length : 0
      60
      *************
      arguments args length : 2
      arguments kwargs length : 0
      30
      *************
      arguments args length : 3
      arguments kwargs length : 2
      (1, 2, 3)
      {'d': 4, 'x': 5}
      ​
      Process finished with exit code 0

       

    • 带参数的装饰器

      def decrorator_args_func():
          print("This is a warpper function")
      ​
      def decrorator_func(decrorator_func_arg):
          decrorator_func_arg()
          def decr_outter_func(func):
              def decr_inner_func(*args,**kwargs):
                  func(*args,**kwargs)
                  print("I am a decrorator inner function")
              return decr_inner_func
          return decr_outter_func
      ​
      @decrorator_func(decrorator_args_func)
      def warpped_func(a, b):
          print("I am a wapped function")
      ​
      warpped_func('s', 'b')
      ​
      ​
      ######执行结果
      This is a warpper function
      I am a wapped function
      I am a decrorator inner function
      ​
      Process finished with exit code 0

       

  • 如果多个函数被两个装饰器装饰时就报错,因为两个函数名一样,第二个函数再去装饰的话就报错。增加@functools.wraps(f), 可以保持当前装饰器去装饰的函数的 name 的值不变

    import functools
    ​
    def user_login_data(f):
        @functools.wraps(f)
        def wrapper(*args, **kwargs):
            return f(*args, **kwargs)
    ​
        return wrapper
    ​
    ​
    @user_login_data
    def num1():
        print("aaa")
    ​
    ​
    @user_login_data
    def num2():
        print("bbbb")
    ​
    ​
    if __name__ == '__main__':
        print(num1.__name__)
        print(num2.__name__)
        
    ######执行结果    
    num1
    num2
    ​
    Process finished with exit code 0

     

2. 类装饰器

  • 类装饰器概念:类装饰器的装饰方法跟函数装饰器相同,都是使用@语法,但是由于类本身不可直接被调用执行,因此必须在类中实现call( )方法。

  • 类装饰器的分类:

    • 装饰无参数的类装饰器

      # 仅执行函数
      class FuncLog():
          def __init__(self, func):
              print('exec funcLog __init__')
              self._func = func
          # 类装饰器中,要有call方法
          def __call__(self):
              print('exec funcLog __call__')
              return self._func()  #当有return时,适用于有返回和无返回的函数
      ​
      @FuncLog
      def demoFunc():
          print( 'This is a demo function......')
      ​
      @FuncLog
      def demoFunc2():
          return 'This is a demo function......'
      ​
      demoFunc()
      print(demoFunc2())
      ​
      #########执行结果
      exec funcLog __init__
      exec funcLog __init__
      exec funcLog __call__
      This is a demo function......
      exec funcLog __call__
      This is a demo function.....1111.
      ​
      Process finished with exit code 0

       

    • 装饰有参数的类装饰器

      # 执行函数,被修饰函数存在参数
      class FuncLog():
          def __init__(self, func):
              print('exec funcLog __init__')
              self._func = func
          # 类装饰器中,要有call方法
          def __call__(self, *args, **kwargs):
              print('exec funcLog __call__')
              print('function args : %s '% args)
              self._func(*args, **kwargs)
      @FuncLog
      def demoFunc(func_args):
          print('This is a demo function, Args is : %s' % func_args)
      ​
      demoFunc('20190726')
      ​
      ​
      #########执行结果
      exec funcLog __init__
      exec funcLog __call__
      function args : 20190726 
      This is a demo function, Args is : 20190726
      ​
      Process finished with exit code 0

       

    • 装饰有参数的类装饰器,并且装饰器有参数

      import functools
      # 执行函数,被修饰函数存在参数,并且装饰器有入参
      class FuncLog():
          def __init__(self, func_log_arg):
              print('exec funcLog __init__')
              self._func_log_arg = func_log_arg
      ​
          # 类装饰器中,要有call方法
          def __call__(self, func):
              print('exec funcLog __call__')
              print('decr args is :%s' % self._func_log_arg)
              @functools.wraps(func)
              def wrapper(*args, **kwargs):
                  print('function args : %s ' % args)
                  return func(*args, **kwargs)
              return wrapper
      @FuncLog('decr_log')
      def demoFunc(func_args):
          print('This is a demo function, Args is : %s' % func_args)
      ​
      demoFunc('20190726')
      print(demoFunc.__name__)
      ​
      ​
      ​
      ###########执行结果
      exec funcLog __init__
      exec funcLog __call__
      decr args is :decr_log
      function args : 20190726 
      This is a demo function, Args is : 20190726
      demoFunc
      ​
      Process finished with exit code 0

       

3. super关键字

  • 定义: super([type[, object-or-type]]) ,super() 在使用时至少传递一个参数,且这个参数必须是一个类。通过super()获取到的是一个代理对象,通过这个对象去查找父类或者兄弟类的方法。

  • 集中常用的写法:

    • super()不写参数的情况:super() 在一个定义的类中使用时,可以不写参数,Python会自动根据情况将两个参数传递给super。在Python3中的类都是新式类,广度优先的查找顺序,在定义一个类时就会生成一个MRO列表(经典类没有MRO列表,深度优先),查找顺序就是按照这个列表中的类的顺序从左到右进行的。

      class Base:
          def __init__(self):
              print('Base.__init__')
      
      
      class A(Base):
          def __init__(self):
              super().__init__()
              print('A.__init__')
      
      
      class B(Base):
          def __init__(self):
              super().__init__()
              print('B.__init__')
      
      
      class C(Base):
          def __init__(self):
              super().__init__()
              print('C.__init__')
      
      
      class D(A, B, C):
          def __init__(self):
              super().__init__()  # 等同于 super(D, self).__init__()
              print('D.__init__')
      
      
      D()
      
      print(D.mro())
      
      
      #结果
      Base.__init__
      C.__init__
      B.__init__
      A.__init__
      D.__init__
      [<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Base'>, <class 'object'>]

       

    • super(type) 只传递一个参数的情况:super() 只传递一个参数时,是一个不绑定的对象,不绑定的话它的方法是不会有用的

      class Base:
          def __init__(self):
              print('Base.__init__')
      
      
      class A(Base):
          def __init__(self):
              super().__init__()
              print('A.__init__')
      
      
      class B(Base):
          def __init__(self):
              super().__init__()
              print('B.__init__')
      
      
      class C(Base):
          def __init__(self):
              super().__init__()
              print('C.__init__')
      
      
      class D(A, B, C):
          def __init__(self):
              super(B).__init__()  # 值传递一个参数
              print('D.__init__')
      
      
      D()
      
      print(D.mro())
      
      #结果
      D.__init__
      [<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Base'>, <class 'object'>]

       

    • super(type, obj) 传递一个类和一个对象的情况:super() 的参数为一个类和一个对象的时候,得到的是一个绑定的super对象。但是obj必须是type的实例或者是子类的实例。 从结果可以看出,只是查找了B类之后的类的方法,即super()是根据第二个参数(obj)来计算MRO,根据顺序查找第一个参数(类)之后的类的方法

      class Base:
          def __init__(self):
              print('Base.__init__')
      
      
      class A(Base):
          def __init__(self):
              super().__init__()
              print('A.__init__')
      
      
      class B(Base):
          def __init__(self):
              super().__init__()
              print('B.__init__')
      
      
      class C(Base):
          def __init__(self):
              super().__init__()
              print('C.__init__')
      
      
      class D(A, B, C):
          def __init__(self):
              super(B, self).__init__()  # self是B的子类D的实例
              print('D.__init__')
      
      
      D()
      
      print(D.mro())
      
      #结果
      Base.__init__
      C.__init__
      D.__init__
      [<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Base'>, <class 'object'>]

       

    • super(type1, type2) 传递两个类的情况:super()传递两个类type1和type2时,得到的也是一个绑定的super对象,但这需要type2是type1的子类,且如果调用的方法需要传递参数时,必须手动传入参数,因为super()第二个参数是类时,得到的方法是函数类型的,使用时不存在自动传参,第二个参数是对象时,得到的是绑定方法,可以自动传参。

      class Base:
          def __init__(self):
              print('Base.__init__')
      
      
      class A(Base):
          def __init__(self):
              super().__init__()
              print('A.__init__')
      
      
      class B(Base):
          def __init__(self):
              super().__init__()
              print('B.__init__')
      
      
      class C(Base):
          def __init__(self):
              super().__init__()
              print('C.__init__')
      
      
      class D(A, B, C):
          def __init__(self):
              super(B, D).__init__(self)  # D是B的子类,并且需要传递一个参数
              print(type(super(B, D).__init__))  #返回的Function,需要自己填充参数
              print(type(super(B, self).__init__)) #返回的是method,python自动填充参数
              print('D.__init__')
      
      
      D()
      
      print(D.mro())
      
      
      #结果
      Base.__init__
      C.__init__
      <class 'function'>
      <class 'method'>
      D.__init__
      [<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Base'>, <class 'object'>]
      

       

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章