JS Proxy 與 Object.defineProperty 的區別
阿新 • • 發佈:2020-12-18
技術標籤:Python
文章目錄
裝飾器
先來看一個程式碼段:
def announce(f):
def wrapper(name):
print("start to run the function...")
f(name)
print("Done with the function.")
return wrapper
@announce
def hello(name):
print(f"hello, {name}" )
name = "Sudley"
print(f"function name: {hello.__name__}")
hello(name)
@announce就是裝飾器,通過裝飾器可以快速的給函式新增功能。裝飾器讓你在一個函式的前後去執行程式碼。
上面是裝飾器可以理解為hello=announce(hello),所以hello(name)相當於wrapper(name)
上面檢視hello的函式名稱是announce中返回的函式名稱wrapper,也行你想hello依然是hello可以使用functools.wraps來修飾一下,@wraps
from functools import wraps
def announce(f):
@wraps(f)
def wrapper(name):
print("start to run the function...")
f(name)
print("Done with the function.")
return wrapper
@announce
def hello(name):
print(f"hello, {name}")
name = "Sudley"
print(f"function name: {hello.__name__}")
hello(name)
裝飾器常見用法舉例
日誌(logging):
平常肯會遇到需要定義函式開始執行和介紹執行的日誌,如
import logging
logging.basicConfig(level=logging.INFO)
def square_func(x):
logging.info("square_func was called")
return x * x
def add_func(x, y):
logging.info("add_func was called")
return x + y
s_result = square_func(4)
a_result = add_func(2, 3)
print(s_result, a_result)
可以看到上面的logging.info有一點壞味道,程式碼重複了,這時就可以用到裝飾器進行優化,如下
from functools import wraps
import logging
logging.basicConfig(level=logging.INFO)
def logit(func):
@wraps(func)
def with_called_logging(*args, **kwargs):
logging.info(func.__name__ + " was called")
return func(*args, **kwargs)
return with_called_logging
@logit
def square_func(x):
return x * x
@logit
def add_func(x, y):
return x + y
s_result = square_func(4)
a_result = add_func(2, 3)
print(s_result, a_result)
帶引數的裝飾器
前面我們用到的@wraps(func)就是帶引數的裝飾器,允許傳入func引數,下面我們定義一個類似的裝飾器。在前面日誌的基礎上允許新增日誌級別的引數。
import logging
logging.basicConfig(level=logging.INFO)
def logit(level="info"):
def decorator(func):
def with_called_logging(*args, **kwargs):
if level == "info":
logging.info(func.__name__ + " was called")
elif level == "warn":
logging.warn(func.__name__ + " was called")
return func(*args, **kwargs)
return with_called_logging
return decorator
@logit()
def square_func(x):
return x * x
@logit("warn")
def add_func(x, y):
return x + y
s_result = square_func(4)
a_result = add_func(2, 3)
print(s_result, a_result)
這裡相比之前多封裝了一層函式,可以理解為含有引數的閉包。
由於logit()=decorator
所以@logit()、@logit(“warn”)都等於@decorator,日誌級別相關引數通過閉包的形式傳入。
類裝飾器
裝飾器不僅可以是函式,還可以是類,相比函式裝飾器,類裝飾器具有靈活度大、高內聚、封裝性等優點。使用類裝飾器主要依靠類的__call__方法,當使用 @ 形式將裝飾器附加到函式上時,就會呼叫此方法。
import logging
logging.basicConfig(level=logging.INFO)
def logit(level="info"):
class decorator(object):
def __init__(self, func, level = "info"):
self.level = level
self._func = func
def __call__(self,*args):
if self.level == "info":
logging.info(self._func.__name__ + " was called")
elif self.level == "warn":
logging.warn(self._func.__name__ + " was called")
return self._func(*args)
return decorator
@logit()
def square_func(x):
return x * x
@logit(level = "warn")
def add_func(x, y):
return x + y
s_result = square_func(4)
a_result = add_func(2, 3)
print(s_result, a_result)
__call__方法(補充知識點)
建立型別的時候定義了__call__()方法,這個型別就是可呼叫的。
import logging
logging.basicConfig(level=logging.INFO)
class decorator(object):
def __init__(self, func, level = "info"):
self.level = level
self._func = func
def __call__(self,*args):
if self.level == "info":
logging.info(self._func.__name__ + " was called")
elif self.level == "warn":
logging.warn(self._func.__name__ + " was called")
return self._func(*args)
#@decorator
def square_func(x):
return x * x
square_func = decorator(square_func)
print(type(square_func))
s_result = square_func(4) #類的例項可以直接呼叫
print(s_result)
不含__call__方法的型別舉例:
import logging
logging.basicConfig(level=logging.INFO)
class decorator(object):
def __init__(self, func, level = "info"):
self.level = level
self._func = func
def not_call(self,*args):
if self.level == "info":
logging.info(self._func.__name__ + " was called")
elif self.level == "warn":
logging.warn(self._func.__name__ + " was called")
return self._func(*args)
#@decorator
def square_func(x):
return x * x
square_func = decorator(square_func)
print(type(square_func))
try:
s_result = square_func(4)
except TypeError as e:
print(e)
s_result = square_func.not_call(4)
print(s_result)