1. 程式人生 > 實用技巧 >JS Proxy 與 Object.defineProperty 的區別

JS Proxy 與 Object.defineProperty 的區別

技術標籤: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)

在這裡插入圖片描述