午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

裝飾器是怎么實(shí)現(xiàn)的?

 古明地覺(jué)O_o 2024-11-28 發(fā)布于北京

裝飾器是 Python 的一個(gè)亮點(diǎn),但并不神秘,因?yàn)樗举|(zhì)上就是高階函數(shù)加上閉包,只不過(guò)給我們提供了一個(gè)優(yōu)雅的語(yǔ)法糖。

至于為什么要有裝飾器,我覺(jué)得有句話說(shuō)的非常好,裝飾器存在的最大意義就是可以在不改動(dòng)原函數(shù)的代碼和調(diào)用方式的情況下,為函數(shù)增加一些新的功能。

def deco(func):
    print("都閃開(kāi),我要開(kāi)始裝飾了")

    def inner(*args, **kwargs):
        print("開(kāi)始了")
        ret = func(*args, **kwargs)
        print("結(jié)束")
        return ret

    return inner

# 這一步等價(jià)于 foo = deco(foo)
# 因此上來(lái)就會(huì)打印 deco 里面的 print
@deco
def foo(a, b):
    print(f"a = {a},b = ")
print("---------")
"""
都閃開(kāi),我要開(kāi)始裝飾了
---------
"""


# 此時(shí)再調(diào)用 foo,已經(jīng)不再是原來(lái)的 foo 了
# 而是 deco 里面的閉包 inner
foo(12)
"""
開(kāi)始了
a = 1,b = 2
結(jié)束
"""

如果不使用裝飾器的話:

def deco(func):
    print("都閃開(kāi),我要開(kāi)始裝飾了")

    def inner(*args, **kwargs):
        print("開(kāi)始了")
        ret = func(*args, **kwargs)
        print("結(jié)束")
        return ret

    return inner

def foo(a, b):
    print(f"a = {a},b = ")

foo = deco(foo)
"""
都閃開(kāi),我要開(kāi)始裝飾了
"""

foo(12)
"""
開(kāi)始了
a = 1,b = 2
結(jié)束
"""

打印結(jié)果告訴我們,裝飾器只是類似于 foo=deco(foo) 的一個(gè)語(yǔ)法糖罷了。

至于字節(jié)碼這里就不看了,還是那句話,只是個(gè)語(yǔ)法糖,它和我們直接調(diào)用 foo=deco(foo) 是等價(jià)的,所以理解裝飾器(decorator)的關(guān)鍵就在于理解閉包(closure)。

另外函數(shù)在被裝飾器裝飾之后,整個(gè)函數(shù)其實(shí)就已經(jīng)變了,而為了保留原始信息我們一般會(huì)從 functools 模塊中導(dǎo)入一個(gè) wraps 函數(shù)。當(dāng)然裝飾器還可以寫(xiě)的更復(fù)雜,比如帶參數(shù)的裝飾器、類裝飾器等等,不過(guò)這些都屬于 Python 層級(jí)的東西了,我們就不說(shuō)了。

另外裝飾器還可以不止一個(gè),如果一個(gè)函數(shù)被多個(gè)裝飾器裝飾,會(huì)有什么表現(xiàn)呢?

def deco1(func):
    def inner():
        return f"<deco1>{func()}</deco1>"
    return inner

def deco2(func):
    def inner():
        return f"<deco2>{func()}</deco2>"
    return inner

def deco3(func):
    def inner():
        return f"<deco3>{func()}</deco3>"
    return inner

@deco1
@deco2
@deco3
def foo():
    return "古明地覺(jué)"

print(foo())

解釋器還是從上到下解釋,當(dāng)執(zhí)行到 @deco1 的時(shí)候,肯定要裝飾了,但它下面不是函數(shù),也是一個(gè)裝飾器,于是表示:要不哥們,你先裝飾。然后執(zhí)行 @deco2,但它下面還是一個(gè)裝飾器,于是重復(fù)了剛才的話,把皮球踢給 @deco3。

當(dāng)執(zhí)行 @deco3 的時(shí)候,發(fā)現(xiàn)下面終于是一個(gè)普通的函數(shù)了,于是裝飾了。

deco3 裝飾完畢之后,foo = deco3(foo)。然后 deco2 發(fā)現(xiàn) deco3 已經(jīng)裝飾完畢,那么會(huì)對(duì) deco3 裝飾的結(jié)果再進(jìn)行裝飾,此時(shí) foo = deco2(deco3(foo));同理,再經(jīng)過(guò) deco1 的裝飾,最終得到了 foo  =  deco1(deco2(deco3(foo)))。

于是最終輸出:

<deco1><deco2><deco3>古明地覺(jué)</deco3></deco2></deco1>

所以當(dāng)有多個(gè)裝飾器的時(shí)候,會(huì)從下往上裝飾;然后執(zhí)行的時(shí)候,會(huì)從上往下執(zhí)行。

以上就是裝飾器相關(guān)的內(nèi)容,可以說(shuō)非常簡(jiǎn)單了,甚至有點(diǎn)水文章的嫌疑,因?yàn)楹诵亩荚谏弦黄榻B的閉包當(dāng)中。還是那句話,理解裝飾器的關(guān)鍵就在于理解閉包。

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多