原理 裝飾器本質也是一個函數, 只不過這個函數需要遵循以下規則: 入參只能有一個,類型為函數。 被裝飾的函數將入會被傳入這個參數 返回值是必須是一個函數, 屆時被調用的時候實際上調用的是返回出來的這個函數,所以返回的函數入參通常是 以滿足所有函數需要 之後通過@語法糖即可裝飾到任意函數上 簡單裝飾器 ...
原理
裝飾器本質也是一個函數, 只不過這個函數需要遵循以下規則:
- 入參只能有一個,類型為函數。 被裝飾的函數將入會被傳入這個參數
- 返回值是必須是一個函數, 屆時被調用的時候實際上調用的是返回出來的這個函數,所以返回的函數入參通常是
(*args, **kwargs):
以滿足所有函數需要
之後通過@語法糖即可裝飾到任意函數上
簡單裝飾器例子
# 不帶參數的裝飾器
def pre_do_sth(func):
def wrapper(*args, **kwargs):
print("Do sth before call one")
func(*args, **kwargs)
return wrapper
@pre_do_sth
def echo(msg):
print(msg)
echo("Hello World")
運行結果
Do sth before call one
Hello World
實際上調用的是 wrapper("Hello World") --> echo("Hello World")
帶參數的裝飾器例子(參數控制的是裝飾器的行為)
只需要寫一個返回 裝飾器(入參只有一個, 返回值是一個函數)函數的函數
同樣也能利用@語法糖
# 帶參數的裝飾器
def pre_do_sth_2(msg):
def decorator(func):
def wrapper(*args, **kwargs):
print("Do sth before call two, print:%s"%(msg))
func(*args, **kwargs)
return wrapper
return decorator
@pre_do_sth_2("Foo")
def echo(msg):
print(msg)
echo("Hello World")
實際上@後面並不是對pre_do_sth_2這個函數生效 而是對pre_do_sth_2的返回值生效
運行結果
Do sth before call two, print:Foo
Hello World
多個裝飾器調用順序
先聲明的裝飾器先執行, 即在最外層
# 不帶參數的裝飾器
def pre_do_sth(func):
def wrapper(*args, **kwargs):
print("Do sth before call one")
func(*args, **kwargs)
return wrapper
# 帶參數的裝飾器
def pre_do_sth_2(msg):
def decorator(func):
def wrapper(*args, **kwargs):
print("Do sth before call two, print:%s"%(msg))
func(*args, **kwargs)
return wrapper
return decorator
@pre_do_sth
@pre_do_sth_2("Foo")
def echo(msg):
print(msg)
echo("Hello World")
運行結果
Do sth before call one
Do sth before call two, print:Foo
Hello World