国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

簡單聊聊Python中的wraps修飾器

Jensen / 3335人閱讀

摘要:首先說函數,在官方文檔的描述中,這個函數的聲明如下。這是因為給添加上修飾器相當于執行了一句,執行完這條語句之后,函數就變成了函數。自定義修飾器我們對上面定義的修飾器稍作修改,添加了一句。參考鏈接裝飾器和模塊源碼

預備知識

在了解wraps修飾器之前,我們首先要了解partialupdate_wrapper這兩個函數,因為在wraps的代碼中,用到了這兩個函數。

partial

首先說partial函數,在官方文檔的描述中,這個函數的聲明如下:functools.partial(func, *args, **keywords)。它的作用就是返回一個partial對象,當這個partial對象被調用的時候,就像通過func(*args, **kwargs)的形式來調用func函數一樣。如果有額外的 位置參數(args) 或者 關鍵字參數(*kwargs) 被傳給了這個partial對象,那它們也都會被傳遞給func函數,如果一個參數被多次傳入,那么后面的值會覆蓋前面的值。

個人感覺這個函數很像C++中的bind函數,都是把某個函數的某個參數固定,從而構造出一個新的函數來。比如下面這個例子:

from functools import partial

def add(x:int, y:int):
    return x+y

# 這里創造了一個新的函數add2,只接受一個整型參數,然后將這個參數統一加上2
add2 = partial(add, y=2)

add2(3)  # 這里將會輸出5

這個函數是使用C而不是Python實現的,但是官方文檔中給出了Python實現的代碼,如下所示,大家可以進行參考:

def partial(func, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = keywords.copy()
        newkeywords.update(fkeywords)
        return func(*args, *fargs, **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    return newfunc
update_wrapper

接下來,我們再來聊一聊update_wrapper這個函數,顧名思義,這個函數就是用來更新修飾器函數的,具體更新些什么呢,我們可以直接把它的源碼搬過來看一下:

WRAPPER_ASSIGNMENTS = ("__module__", "__name__", "__qualname__", "__doc__",
                       "__annotations__")
WRAPPER_UPDATES = ("__dict__",)
def update_wrapper(wrapper,
                   wrapped,
                   assigned = WRAPPER_ASSIGNMENTS,
                   updated = WRAPPER_UPDATES):
    for attr in assigned:
        try:
            value = getattr(wrapped, attr)
        except AttributeError:
            pass
        else:
            setattr(wrapper, attr, value)
    for attr in updated:
        getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
    wrapper.__wrapped__ = wrapped
    return wrapper

大家可以發現,這個函數的作用就是從 被修飾的函數(wrapped) 中取出一些屬性值來,賦值給 修飾器函數(wrapper) 。為什么要這么做呢,我們看下面這個例子。

自定義修飾器v1

首先我們寫個自定義的修飾器,沒有任何的功能,僅有文檔字符串,如下所示:

def wrapper(f):
    def wrapper_function(*args, **kwargs):
        """這個是修飾函數"""
        return f(*args, **kwargs)
    return wrapper_function
    
@wrapper
def wrapped():
    """這個是被修飾的函數"""
    print("wrapped")

print(wrapped.__doc__)  # 輸出`這個是修飾函數`
print(wrapped.__name__)  # 輸出`wrapper_function`

從上面的例子我們可以看到,我想要獲取wrapped這個被修飾函數的文檔字符串,但是卻獲取成了wrapper_function的文檔字符串,wrapped函數的名字也變成了wrapper_function函數的名字。這是因為給wrapped添加上@wrapper修飾器相當于執行了一句wrapped = wrapper(wrapped),執行完這條語句之后,wrapped函數就變成了wrapper_function函數。遇到這種情況該怎么辦呢,首先我們可以手動地在wrapper函數中更改wrapper_function__doc____name__屬性,但聰明的你肯定也想到了,我們可以直接用update_wrapper函數來實現這個功能。

自定義修飾器v2

我們對上面定義的修飾器稍作修改,添加了一句update_wrapper(wrapper_function, f)

from functools import update_wrapper

def wrapper(f):
    def wrapper_function(*args, **kwargs):
        """這個是修飾函數"""
        return f(*args, **kwargs)
    update_wrapper(wrapper_function, f)  # <<  添加了這條語句
    return wrapper_function
    
@wrapper
def wrapped():
    """這個是被修飾的函數"""
    print("wrapped")


print(wrapped.__doc__)  # 輸出`這個是被修飾的函數`
print(wrapped.__name__)  # 輸出`wrapped`

此時我們可以發現,__doc____name__屬性已經能夠按我們預想的那樣顯示了,除此之外,update_wrapper函數也對__module____dict__等屬性進行了更改和更新。

wraps修飾器

OK,至此,我們已經了解了partialupdate_wrapper這兩個函數的功能,接下來我們翻出wraps修飾器的源碼:

WRAPPER_ASSIGNMENTS = ("__module__", "__name__", "__qualname__", "__doc__",
                       "__annotations__")
WRAPPER_UPDATES = ("__dict__",)
def wraps(wrapped,
          assigned = WRAPPER_ASSIGNMENTS,
          updated = WRAPPER_UPDATES):
    return partial(update_wrapper, wrapped=wrapped,
                   assigned=assigned, updated=updated)

沒錯,就是這么的簡單,只有這么一句,我們可以看出,wraps函數其實就是一個修飾器版的update_wrapper函數,它的功能和update_wrapper是一模一樣的。我們可以修改我們上面的自定義修飾器的例子,做出一個更方便閱讀的版本。

自定義修飾器v3
from functools import wraps

def wrapper(f):
    @wraps(f)
    def wrapper_function(*args, **kwargs):
        """這個是修飾函數"""
        return f(*args, **kwargs)
    return wrapper_function
    
@wrapper
def wrapped():
    """這個是被修飾的函數
    """
    print("wrapped")

print(wrapped.__doc__)  # 輸出`這個是被修飾的函數`
print(wrapped.__name__)  # 輸出`wrapped`

至此,我想大家應該明白wraps這個修飾器的作用了吧,就是將 被修飾的函數(wrapped) 的一些屬性值賦值給 修飾器函數(wrapper) ,最終讓屬性的顯示更符合我們的直覺。

參考鏈接

python3 functools.wraps

python裝飾器和functools模塊

Github - cpython functools源碼

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/44369.html

相關文章

  • Python有什么好學的》之修飾

    摘要:然后煎魚加了一個后再調用函數,得到的輸出結果和加修飾器的一樣,換言之等效于因此,我們對于,可以理解是,它通過閉包的方式把新函數的引用賦值給了原來函數的引用。 Python有什么好學的這句話可不是反問句,而是問句哦。 主要是煎魚覺得太多的人覺得Python的語法較為簡單,寫出來的代碼只要符合邏輯,不需要太多的學習即可,即可從一門其他語言跳來用Python寫(當然這樣是好事,誰都希望入門簡...

    lewinlee 評論0 收藏0
  • PyTips 0x0f - Python 修飾與 functools

    項目地址:https://git.io/pytips Python 的修飾器是一種語法糖(Syntactic Sugar),也就是說: @decorator @wrap def func(): pass 是下面語法的一種簡寫: def func(): pass func = decorator(wrap(func)) 關于修飾器的兩個主要問題: 修飾器用來修飾誰 誰可以作為修飾器...

    dingding199389 評論0 收藏0
  • Python裝飾

    摘要:一引用書流暢的書二基本概念問題裝飾器是什么解答嚴格來說,裝飾器只是語法糖,裝飾器是可調用的對象,可以像常規的可調用對象那樣調用,特殊的地方是裝飾器的參數是一個函數問題裝飾器有什么特性解答裝飾器有個特性,一是可以把被裝飾的函數替換成其他函數, 一, 引用 [書] 流暢的Python [書] Effective Python 二, 基本概念 showImg(https://segme...

    aisuhua 評論0 收藏0
  • Python: 會打扮的裝飾

    摘要:一般情況下,我們使用裝飾器提供的語法糖,來簡化上面的寫法像上面的情況,可以動態修改函數或類功能的函數就是裝飾器。本文標題為會打扮的裝飾器本文鏈接為參考資料修飾器的函數式編程中的裝飾器介紹思誠之道裝飾器入門與提高賴明星 裝飾器 我們知道,在 Python 中,我們可以像使用變量一樣使用函數: 函數可以被賦值給其他變量 函數可以被刪除 可以在函數里面再定義函數 函數可以作為參數傳遞給另外...

    blastz 評論0 收藏0
  • python中的裝飾

    摘要:的裝飾器是用來裝飾函數的。簡單裝飾器裝飾器的語法糖是使用符號表示,裝飾器本身也是一個函數,只不過參數是函數而已。保留函數的元信息被修飾之后的函數,它的元信息都消失,被替換的函數代替。中提供了來保存函數的元信息。 python的裝飾器是用來裝飾函數的。這是什么意思呢?假如我們有一個函數,這個函數的功能不能滿足我們現有的需求,那么我們可以通過裝飾器在這個函數執行前執行后做一些我們需要的操作...

    張金寶 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<