python函數語言程式設計3(裝飾器的深入理解)

水痕001發表於2019-02-26

一、什麼是裝飾器

  • 1、python中裝飾器可以理解為AOP程式設計,有點類似Spring中的註解,在不改變原函式或類的基礎上,對函式或類新增額外(自己需求補充)的功能。
  • 2、裝飾器本質上是一個函式,該函式用來處理其他函式,它可以讓其他函式在不需要修改程式碼的前提下增加額外的功能,裝飾器的返回值也是一個函式物件。
  • 3、有了裝飾器,我們就可以抽離出大量與函式功能本身無關的雷同程式碼並繼續重用。
  • 4、比如我們要給每一個函式新增一個列印logger日誌,我們就可以使用裝飾器,在不修改原函式的前提下,新增功能又能做到程式碼的解耦。

二、裝飾器的幾個原則及學習裝飾器必要的知識儲備

三、裝飾器的演變過程

  • 1、定義一個裝飾器(計算函式執行時間)

    import time
    
    def timer(func):
    	def wrapper():
          start_time = time.time()
          res = func()
          end_time = time.time()
          print(`程式執行時間:{0}`.format(end_time - start_time))
          return res
      return wrapper
    複製程式碼
  • 2、定義一個要執行的函式

    def foo():
        time.sleep(3)
        print(`主函式`)
    複製程式碼
  • 3、根據上面幾個原則,我們來呼叫函式foo

    if __name__ == "__main__":
    		# 1.timer函式中傳遞函式foo進去
    		# 2.為了不改變函式的呼叫方式,將timer函式的返回值(函式)賦值給變數foo
        foo = timer(foo) # 前面foo是新定義的變數,timer中的foo是上面定義的foo函式
        foo() # timer是一個高階函式,返回的是一個函式
    複製程式碼
  • 4、解答上面的程式碼

    • 1.定義的裝飾器是一個高階函式,被裝飾的函式作為引數傳遞進去
    • 2.在滿足裝飾的原則下,我們把高階函式執行後重新賦值給foo函式
    • 3.foo()函式的執行就沒改變原有函式的呼叫方式
  • 5、使用裝飾器**@**

上面第四點中2和3步驟在python中直接使用**@**語法糖來處理

@timer
def bar():
    time.sleep(2)
    print(`主函式`)
  
if __name__ == "__main__":
    bar()
複製程式碼

四、裝飾器中傳遞引數

import time

def timer(func):
  def wrapper(*args, **kwargs):
      start_time = time.time()
      res = func(*args, **kwargs)
      end_time = time.time()
      print(`執行時間:{0}`.format(end_time - start_time))
      return res

  return wrapper

@timer
def foo(name, gender):
  time.sleep(3)
  print(name)
  print(gender)

if __name__ == "__main__":
  foo(`張三`, gender=`男`)
複製程式碼

五、使用類來作裝飾器

建立一個資料庫操的log的裝飾器

  • 1、具體實現程式碼

    from functools import wraps
    from datetime import datetime
    
    # 建立一個類的裝飾器
    class Log(object):
        def __init__(self, logfile=`log.log`):
            self.logfile = logfile
    
        def __call__(self, func):
            @wraps(func)
            def wrapper(*args, **kwargs):
                self.writelog(*args, **kwargs)
                return func(*args, **kwargs)
    
            return wrapper
    
        # 把日誌寫到本地
        def writelog(self, *args, **kwargs):
            time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            log_str = time + ` 操作人:{0[0]} 進行了【{0[1]}】操作`.format(args)
            # 寫入本地檔案中
            with open(self.logfile, `a`, encoding=`utf8`) as file:
                file.write(log_str + `
    `)
    
    @Log()
    def printLog(name, type):
        print(`姓名:{0},type:{1}`.format(name, type))
    
    if __name__ == "__main__":
        printLog(`張三`, `查詢`)
        printLog(`李四`, `新增`)
    複製程式碼
  • 2、執行結果(本地資料夾下多一個檔案)

    2018-06-24 10:47:40 操作人:張三 進行了【查詢】操作
    2018-06-24 10:47:40 操作人:李四 進行了【新增】操作
    複製程式碼
更多原著博文請參考

相關文章