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'>]
      

       

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