Python裝飾器
1、裝飾器的本質
裝飾器本質上是一個閉包函數,可以讓其他函數在不需要任何程式碼變動的前提下增加額外功能,裝飾器的返回值也是一個函數。
-
閉包函數
1)必須是嵌套函數,即外函數中定義了一個內函數;
2)內函數引用了外函數作用域中(注意:非全局)的變數;
3)外函數的返回值是內函數的引用;
4)檢測函數是否為閉包函數:
function.__closure__
,是閉包,返回一個cell
,不是閉包,返回None
; -
函數
1)什麼是函數:組織好的、可重複使用的,用來實現單一或相關聯功能的程式碼段;
2)函數的優點:函數能提高應用的模組性和程式碼的重複利用率;
3)函數的定義:使用
def
關鍵字;def func(): print("Hello, World!")
4)函數的參數:根據函數在定義時和調用時,函數的參數有不同的概念;
- 定義時:位置參數、默認參數、不定長參數;
def func(a, b=0, *args, **kwargs): print(f"位置參數:{a}") print(f"默認參數:{b}") print(f"不定長參數:元組{args},字典{kwargs}")
- 調用時:必備參數(必須傳)、關鍵字參數(可傳可不傳)、不定長參數(可傳可不傳);
func("Hello") # "Hello" >> a func("Hello", b=1) # "Hello" >> a, 1 >> b func("Hello", 2) # "Hello" >> a, 2 >> b func("Hello", 2, 3, c="World") # "Hello" >> a, 2 >> b, 3 >> *args, c="World" >> **kwargs
5)匿名函數:使用
lambda
關鍵字,只是一個表達式,不是程式碼塊,邏輯有限;add = lambda a, b: a + b
6)變數作用域:LEGB;
- L:Local,局部作用域;
- E:Enclosing,閉包函數外的函數中;
- G:Global,全局作用域;
- B:Built-in,內建作用域;
7)有關函數的幾個概念;
- 函數即變數:函數可作為參數,也可作為返回值;
- 高階函數:以函數作為參數或返回值的函數,內置函數
map()
、filter()
、functools
包中的reduce()
; - 嵌套函數:函數里定義函數;
- 嵌套函數中變數的生命周期:正常情況下,一個函數運行結束,函數所有局部對象都會被回收,釋放記憶體。但是閉包是一種特殊情況。閉包中,如果外函數在結束時,外函數作用域中的臨時變數被內函數調用,外函數就會將該變數綁定給內函數,然後再結束;
2、裝飾器應滿足條件
- 給被裝飾函數添加新的功能;
- 不能改變被裝飾函數的程式碼;
- 不能改變被裝飾函數的調用方式;
3、裝飾器的應用場景
- 插入日誌;
- 性能測試;
- 事務處理;
- 快取、許可權校驗;
4、裝飾器的固定格式
-
格式1
def decorator(func): # decorator函數中嵌套了inner函數 def inner(*args, **kwargs): """something before func""" f = func(*args, **kwargs) # 內函數inner調用了外函數decorator作用域中的變數func """something after func""" return f return inner # 外函數decorator的返回值是inner(對內函數inner的引用)
-
格式2
from functools import wraps def decorator(func): @wraps def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper
5、裝飾器的演進
-
將被裝飾的函數顯式傳入裝飾器,被裝飾函數沒有參數和返回值;
import time def func(): print("I'm func.") def timer(f): def inner(): start = time.time() f() end = time.time() print(end - start) return inner func = timer(func) # 將函數func作為參數傳遞給timer裝飾器,將返回結果賦值給變數func func() # func(),即執行了func
-
將被裝飾函數放在語法糖下一行,被裝飾函數不帶參數,沒有返回值;
import time def timer(f): def inner(): start = time.time() f() end = time.time() print(end - start) return inner @timer # @timer被稱為語法糖,等價於func=timer(func) def func(): print("I'm func.") func()
-
將被裝飾函數放在語法糖下一行,被裝飾函數帶1個參數,沒有返回值;
import time def timer(f): def inner(i): start = time.time() f(i) end = time.time() print(end - start) return inner @timer def func(x): print(x) func("Hello, World!")
-
將被裝飾函數放在語法糖下一行,被裝飾函數帶2個參數,沒有返回值;
import time def timer(f): def inner(*args, **kwargs): start = time.time() f(*args, **kwargs) end = time.time() print(end - start) return inner @timer def func(x, y): print(f"The first argument is {x}, the second is {y}.") func(2, 24)
-
將被裝飾函數放在語法糖下一行,被裝飾函數帶多個參數,有返回值;
import time def timer(f): def inner(*args, **kwargs): start = time.time() r = f(*args, **kwargs) end = time.time() print(end - start) return r return inner @timer def func(x, y, z=3): print(f"Arguments are {}、{} and {}.") return 'Over' func(1, 2, z=3) print(func(1, 2, z=3))
-
帶參數的裝飾器,被裝飾函數不帶參數,沒有返回值;
def outer(flag): def decorator(f): def inner(*args, **kwargs): if flag: print("Ahead func") r = f(*args, **kwargs) if flag: print("After func") return r return inner return decorator @outer(True) def func(): print("Hello, World!") func()
-
多個裝飾器裝飾同一個函數,被裝飾函數不帶參數,沒有返回值;
def decorator1(f): def inner(): print('Decorator1, before f') f() print('Decorator1, after f') return inner def decorator2(f): def inner(): print('Decorator2, before f') f() print('Decorator2, after f') return inner @decorator2 @decorator1 def func(): print("I'm func.")
6、裝飾器的總結
Python中的裝飾器一共有4種類型:函數裝飾函數、函數裝飾類、類裝飾函數、類裝飾類;
-
函數裝飾函數:函數作為參數被傳入裝飾器函數中;
def decorator(f): def inner(*args, **kwargs): print(f"function name: {f.__name__}") r = f(*args, **kwargs) return r return inner @decorator # @decorator 等價於 addition=decorator(addition) def addition(x, y): return x + y print(addition(3, 7))
-
函數裝飾類:類作為參數被傳入裝飾器函數中;
def decorator(cls): def inner(*args, **kwargs): print(f"class name: {cls.__name__}") return cls(*args, **kwargs) return inner @decorator # @decorator 等價於 Func=decorator(Func) class Func: def __init__(self, item): self.item = item def func(self): print(f"self.a = {self.a}") f = Func('Hello, World!') f.func()
-
類裝飾函數:函數作為參數被傳入裝飾器類中;
class Decorator: def __init__(self, f): self.f = f def __call__(self, item): print(f"function name: {self.f.__name__}") return self.f(item) @Decorator # @Decorator 等價於 func = Decorator(func).__call__ def func(i): return i print(func("Hello, World!"))
-
類裝飾類:類作為參數被傳入裝飾器類中;
class Decorator: def __init__(self, cls): self.cls = cls def __call__(self, item): print(f"class name: {self.cls.__name__}") return self.cls(item) @Decorator # @Decorator 等價於 Func = Decorator(Func).__call__ class Func: def __init__(self, v): self.v = v def func(self): print(self.v) f = Func("Hello, World!") f.func()