天天看點

【設計模式】裝飾器模式--Python實作裝飾器--閉包

文章目錄

      • 一、閉包
          • 1、什麼是閉包?
          • 2、作用
      • 二、裝飾器 Decorator
        • 1、 概念及特點
          • 1.1 裝飾器概念
          • 1.2 遵循原則
          • 1.3 優點
          • 1.4 缺點
          • 1.5 使用場景
          • 1.6 注意事項
          • 1.7 裝飾器(decorator)功能
        • 2、代碼實作
          • 2.1 被裝飾函數無參數 函數計時的裝飾器:
          • 2.2 被裝飾函數有參數 計時器
          • 2.3 被裝飾的函數有不定長參數

**設計模式(Design pattern)**代表了最佳的實踐,通常被有經驗的面向對象的軟體開發人員所采用。設計模式是軟體開發人員在軟體開發過程中面臨的一般問題的解決方案。

設計模式是一套被反複使用的、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是為了重用代碼、讓代碼更容易被他人了解、保證代碼可靠性。

一、閉包

1、什麼是閉包?

①在函數内部嵌套了一個函數,

②内函數使用了外函數的局部變量,

③并且外函數傳回了内函數的引用,這樣就構成了一個閉包

def outfunc(a, b):
    def innerfunc(x):
        return x * a + b
    return innerfunc  # 傳回閉包的結果,這裡沒有括号
           
Python2 和Python3中,内部函數修改外部函數局部變量有差别。
2、作用

閉包可以提高代碼的複用性,

但需要注意:由于閉包引用了外部函數的局部變量,則外部函數的局部變量沒有及時釋放,消耗記憶體

二、裝飾器 Decorator

1、 概念及特點

1.1 裝飾器概念

裝飾器模式(Decorator Pattern)允許向一個現有的對象添加新的功能,同時又不改變其結構。這種類型的設計模式屬于結構型模式,它是作為現有的類的一個包裝。

這種模式建立了一個裝飾類,用來包裝原有的類,并在保持類方法簽名完整性的前提下,提供了額外的功能。

有了裝飾器就可以抽離出大量的與函數功能本身無關的雷同代碼。

1.2 遵循原則

遵循

開放封閉

原則,該原則也适用于函數式程式設計。

簡單來說,它規定已經實作的功能代碼不允許被修改,但可以被擴充,即:

  • 封閉:已實作的功能代碼塊
  • 開放:對擴充開發
1.3 優點

裝飾類和被裝飾類可以獨立發展,不會互相耦合,裝飾模式是繼承的一個替代模式,裝飾模式可以動态擴充一個實作類的功能。

1.4 缺點

多層裝飾比較複雜。

1.5 使用場景
  • 擴充一個類的功能。
  • 動态增加功能,動态撤銷。
1.6 注意事項

可代替繼承。

1.7 裝飾器(decorator)功能
  • 引入日志
  • 函數執行時間統計
  • 執行函數前預備處理
  • 執行函數後清理功能
  • 權限校驗等場景
  • 緩存

2、代碼實作

2.1 被裝飾函數無參數 函數計時的裝飾器:
import time

def timeit(func):
    def innerfunc():
        start = time.time()
        func()
        end = time.time()
        print('Used :', end - start)
	return innerfunc

@timeit
def foo():
    for i in range(100000):
        pass
    
foo()

           

程式運作到裝飾器的時候,會立即對下面的函數進行裝飾 帶參數的裝飾器:

2.2 被裝飾函數有參數 計時器
from time import ctime, sleep

def timefun(func):
    def wrapped_func(a, b):
        print("%s used at %s" % (func.__name__, ctime()))
        print(a, b)
        func(a, b)
    return wrapped_func

@timefun
def foo(a, b):
    print(a+b)

foo(5, 3)
sleep(2)
foo(3, 5)
           
2.3 被裝飾的函數有不定長參數
from time import ctime, sleep

def timefun(func):
    def wrapped_func(*args, **kwargs):
        print("%s used at %s"%(func.__name__, ctime()))
        func(*args, **kwargs)
    return wrapped_func

@timefun
def foo(a, b, c):
    print(a+b+c)

foo(2, 5, 7)
sleep(2)
foo(2, 6, 8)