溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

編寫裝飾器并保存函數(shù)的元數(shù)據(jù),代碼簡(jiǎn)潔之道

發(fā)布時(shí)間:2020-07-09 01:11:26 來源:網(wǎng)絡(luò) 閱讀:272 作者:AmosH 欄目:編程語言

    軟件開發(fā)中的重要一條真理就是“不要重復(fù)自己的工作”。通常當(dāng)我們需要?jiǎng)?chuàng)建高度重復(fù)的代碼時(shí),都可以尋找到一個(gè)更加優(yōu)雅的解決方案。

1    給函數(shù)添加一個(gè)包裝,讓它做一點(diǎn)額外的工作

    當(dāng)我們需要讓一個(gè)函數(shù)擁有計(jì)時(shí)統(tǒng)計(jì)、打印日志的功能時(shí),往往選擇的方案就是直接在函數(shù)體中增加需要的代碼。這在只有一兩個(gè)函數(shù)的時(shí)候還可以接受,但是如果需要讓一個(gè)項(xiàng)目中的所有函數(shù)都具有這樣的功能時(shí),就會(huì)變得十分繁瑣。

    這時(shí)候,就需要我們使用“裝飾器”了。示例如下:

from functools import wraps
import time

def logit(func):
    '''
    使用裝飾器來打印函數(shù)調(diào)用信息
    '''

    @wraps(func)
    def wrapper(*args, **kwargs):
        print('start func {}'.format(func.__name__),
              time.strftime('at %Y %m %d %H:%M:%S', time.localtime()))
        result = func(*args, **kwargs)
        print('finish func {}'.format(func.__name__),
              time.strftime('at %Y %m %d %H:%M:%S', time.localtime()))
        return result
    return wrapper

    下面是使用演示:

>>> @logit
def countdown(n):
    while(n > 0):
        n -= 1
>>> countdown(10000000)
start func countdown at 2018 09 16 16:45:23
finish func countdown at 2018 09 16 16:45:24

    只需要在函數(shù)定義時(shí)為它增加一個(gè)裝飾器(@logit),這個(gè)函數(shù)就能告訴我們它開始運(yùn)行的時(shí)間以及結(jié)束運(yùn)行的時(shí)間!

    裝飾器其實(shí)就是一個(gè)函數(shù),它可以接受一個(gè)函數(shù)作為輸入并返回一個(gè)新的函數(shù)作為輸出。

    裝飾器內(nèi)部的代碼一般會(huì)涉及創(chuàng)建一個(gè)新的函數(shù),利用*args和**kwargs可以接收任意的參數(shù)。在這個(gè)函數(shù)內(nèi)部,我們調(diào)用原來的輸入函數(shù)(即被包裝的那個(gè)函數(shù),它是裝飾器的輸入?yún)?shù))并返回它的結(jié)果。此時(shí),這個(gè)新創(chuàng)建的wrapper函數(shù)就會(huì)作為裝飾器的結(jié)果返回,取代了原本的函數(shù)。

    需要強(qiáng)調(diào)的一點(diǎn)是,裝飾器一般來說不會(huì)修改調(diào)用的簽名,也不會(huì)修改被包裝函數(shù)返回的結(jié)果。這里使用了*args和**kwargs來確??梢越邮苋魏涡问降妮斎?yún)?shù)。裝飾器的返回值幾乎總是同調(diào)用func(*args,**kwargs)的結(jié)果一致,這里的func就是那個(gè)未被包裝過的原始函數(shù)。

2    那裝飾器函數(shù)中的裝飾器@wraps有什么作用

    裝飾器@wraps可以用來保存底層的元數(shù)據(jù),比如函數(shù)名、文檔字符串、函數(shù)注解以及調(diào)用簽名。

    如果沒有使用該裝飾器,獲取上一個(gè)例子中countdown函數(shù)的元數(shù)據(jù)就會(huì)看起來像這樣:

>>> countdown.__name__
'wrapper'
>>> countdown.__doc__
>>> countdown.__annotations__

    @wraps的另一個(gè)重要特性就是可以通過__wrapped__屬性來訪問那個(gè)被包裝的函數(shù),而該屬性同時(shí)也可以使得裝飾器函數(shù)可以合適的將底層被包裝的函數(shù)的簽名暴露出來:

>>> from inspect import signature
>>> print(signature(countdown))
(n:int)

編寫裝飾器并保存函數(shù)的元數(shù)據(jù),代碼簡(jiǎn)潔之道

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI