成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

簡(jiǎn)單聊聊Python中的wraps修飾器

Jensen / 3343人閱讀

摘要:首先說(shuō)函數(shù),在官方文檔的描述中,這個(gè)函數(shù)的聲明如下。這是因?yàn)榻o添加上修飾器相當(dāng)于執(zhí)行了一句,執(zhí)行完這條語(yǔ)句之后,函數(shù)就變成了函數(shù)。自定義修飾器我們對(duì)上面定義的修飾器稍作修改,添加了一句。參考鏈接裝飾器和模塊源碼

預(yù)備知識(shí)

在了解wraps修飾器之前,我們首先要了解partialupdate_wrapper這兩個(gè)函數(shù),因?yàn)樵?b>wraps的代碼中,用到了這兩個(gè)函數(shù)。

partial

首先說(shuō)partial函數(shù),在官方文檔的描述中,這個(gè)函數(shù)的聲明如下:functools.partial(func, *args, **keywords)。它的作用就是返回一個(gè)partial對(duì)象,當(dāng)這個(gè)partial對(duì)象被調(diào)用的時(shí)候,就像通過(guò)func(*args, **kwargs)的形式來(lái)調(diào)用func函數(shù)一樣。如果有額外的 位置參數(shù)(args) 或者 關(guān)鍵字參數(shù)(*kwargs) 被傳給了這個(gè)partial對(duì)象,那它們也都會(huì)被傳遞給func函數(shù),如果一個(gè)參數(shù)被多次傳入,那么后面的值會(huì)覆蓋前面的值。

個(gè)人感覺這個(gè)函數(shù)很像C++中的bind函數(shù),都是把某個(gè)函數(shù)的某個(gè)參數(shù)固定,從而構(gòu)造出一個(gè)新的函數(shù)來(lái)。比如下面這個(gè)例子:

from functools import partial

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

# 這里創(chuàng)造了一個(gè)新的函數(shù)add2,只接受一個(gè)整型參數(shù),然后將這個(gè)參數(shù)統(tǒng)一加上2
add2 = partial(add, y=2)

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

這個(gè)函數(shù)是使用C而不是Python實(shí)現(xiàn)的,但是官方文檔中給出了Python實(shí)現(xiàn)的代碼,如下所示,大家可以進(jìn)行參考:

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

接下來(lái),我們?cè)賮?lái)聊一聊update_wrapper這個(gè)函數(shù),顧名思義,這個(gè)函數(shù)就是用來(lái)更新修飾器函數(shù)的,具體更新些什么呢,我們可以直接把它的源碼搬過(guò)來(lái)看一下:

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

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

自定義修飾器v1

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

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

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

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

自定義修飾器v2

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

from functools import update_wrapper

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


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

此時(shí)我們可以發(fā)現(xiàn),__doc____name__屬性已經(jīng)能夠按我們預(yù)想的那樣顯示了,除此之外,update_wrapper函數(shù)也對(duì)__module____dict__等屬性進(jìn)行了更改和更新。

wraps修飾器

OK,至此,我們已經(jīng)了解了partialupdate_wrapper這兩個(gè)函數(shù)的功能,接下來(lái)我們翻出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)

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

自定義修飾器v3
from functools import wraps

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

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

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

參考鏈接

python3 functools.wraps

python裝飾器和functools模塊

Github - cpython functools源碼

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/44369.html

相關(guān)文章

  • Python有什么好學(xué)的》之修飾

    摘要:然后煎魚加了一個(gè)后再調(diào)用函數(shù),得到的輸出結(jié)果和加修飾器的一樣,換言之等效于因此,我們對(duì)于,可以理解是,它通過(guò)閉包的方式把新函數(shù)的引用賦值給了原來(lái)函數(shù)的引用。 Python有什么好學(xué)的這句話可不是反問(wèn)句,而是問(wèn)句哦。 主要是煎魚覺得太多的人覺得Python的語(yǔ)法較為簡(jiǎn)單,寫出來(lái)的代碼只要符合邏輯,不需要太多的學(xué)習(xí)即可,即可從一門其他語(yǔ)言跳來(lái)用Python寫(當(dāng)然這樣是好事,誰(shuí)都希望入門簡(jiǎn)...

    lewinlee 評(píng)論0 收藏0
  • PyTips 0x0f - Python 修飾與 functools

    項(xiàng)目地址:https://git.io/pytips Python 的修飾器是一種語(yǔ)法糖(Syntactic Sugar),也就是說(shuō): @decorator @wrap def func(): pass 是下面語(yǔ)法的一種簡(jiǎn)寫: def func(): pass func = decorator(wrap(func)) 關(guān)于修飾器的兩個(gè)主要問(wèn)題: 修飾器用來(lái)修飾誰(shuí) 誰(shuí)可以作為修飾器...

    dingding199389 評(píng)論0 收藏0
  • Python裝飾

    摘要:一引用書流暢的書二基本概念問(wèn)題裝飾器是什么解答嚴(yán)格來(lái)說(shuō),裝飾器只是語(yǔ)法糖,裝飾器是可調(diào)用的對(duì)象,可以像常規(guī)的可調(diào)用對(duì)象那樣調(diào)用,特殊的地方是裝飾器的參數(shù)是一個(gè)函數(shù)問(wèn)題裝飾器有什么特性解答裝飾器有個(gè)特性,一是可以把被裝飾的函數(shù)替換成其他函數(shù), 一, 引用 [書] 流暢的Python [書] Effective Python 二, 基本概念 showImg(https://segme...

    aisuhua 評(píng)論0 收藏0
  • Python: 會(huì)打扮的裝飾

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

    blastz 評(píng)論0 收藏0
  • python中的裝飾

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

    張金寶 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<