Python進(jìn)階|裝飾器的那些事(一)

前言

裝飾器在日志、緩存等應(yīng)用中有廣泛使用,我們首先從之前講解的閉包為出發(fā)點(diǎn),給大家講解裝飾器的那些事。

簡(jiǎn)單的裝飾器

首先我們先復(fù)習(xí)下閉包,可以看做是函數(shù)的嵌套,而且函數(shù)內(nèi)部返回的是函數(shù)對(duì)象。

def nth(exponent):
    def exponent_of(base):
        return base ** exponent
    return exponent_of

square = nth(2)
cube = nth(3)
print(square(5))
print(cube(5))

# 25 5^2
# 125 5^3

這里閉包外部傳入的是具有具體值的參數(shù),如果是傳入的是一個(gè)函數(shù)對(duì)象了?那就完成了一個(gè)簡(jiǎn)單的裝飾器。

def decorator(func):
    def wrapper():
        print('start to decorate')
        func()
        print('start to decorate')
    return wrapper

def test():
    print('welcome to decorate')

test1 = decorator(test)
test1()
#start to decorate
#welcome to decorate
#start to decorate

這段代碼中,test1變量指向了函數(shù)wrapper(),而內(nèi)部函數(shù)wrapper()又調(diào)用了test()函數(shù),因此最后打印了三段文字。

通過@語法糖,可以將上面的代碼寫的更簡(jiǎn)潔、更優(yōu)雅:

def decorator(func):
    def wrapper():
        print('start to decorate')
        func()
        print('start to decorate')
    return wrapper

@decorator
def test():
    print('welcome to decorate')

test()
#start to decorate
#welcome to decorate
#start to decorate

這里的@decorator相當(dāng)于是test1 = decorator(test)語句。

帶有參數(shù)的裝飾器

如果test函數(shù)中需要加入?yún)?shù)的話,我們就需要在wrapper函數(shù)中加入對(duì)應(yīng)的參數(shù):

def decorator(func):
    def wrapper(message):
        print('start to decorate')
        func(message)
        print('start to decorate')
    return wrapper

@decorator
def test(message):
    print(message)

test('hello world')
#start to decorate
#hello world
#start to decorate

但是新的問題來了,如果有一個(gè)新的函數(shù)也需要用到decorator()裝飾器,但是他有兩個(gè)參數(shù),我們?cè)撛趺崔k了?

@decorator
def test2(a,b):
    print(a+b)

那這種情況下,我們就可以使用*args 和 **kwargs。

def decorator(func):
    def wrapper(*args,**kwargs):
        print('start to decorate')
        func(*args,**kwargs)
        print('start to decorate')
    return wrapper
自定義參數(shù)的裝飾器

裝飾器還可以自定義參數(shù),這里需要多一層嵌套,讓內(nèi)部函數(shù)重復(fù)運(yùn)行多次。

def repeat(num):
    def decorator(func):
        def wrapper(*args,**kwargs):
            print('start to decorate')
            for i in range(num):
                func(*args,**kwargs)
            print('start to decorate')
        return wrapper
    return decorator

@repeat(3)
def test(message):
    print(message)

test('hello world')

#start to decorate
#hello world
#hello world
#hello world
#start to decorate
有趣的現(xiàn)象

使用了裝飾器后,有一個(gè)有趣的現(xiàn)象,那就是被裝飾的函數(shù)的元信息被改變了。

print(test.__name__)
# wrapper

我們也可以通過@functools.wraps(func)內(nèi)置的裝飾器,保留原函數(shù)的元信息。

import functools

def decorator(func):
    @functools.wraps(func)
    def wrapper(*args,**kwargs):
        print('start to decorate')
        func(*args,**kwargs)
        print('start to decorate')
    return wrapper

@decorator
def test(message):
    print(message)

print(test.__name__)
# test
總結(jié)

本文從閉包出發(fā),講解了裝飾器的定義和使用,其實(shí)裝飾器的作用就是:通過裝飾器函數(shù),可以對(duì)原函數(shù)的功能進(jìn)行修改,而不去修改原函數(shù)代碼。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 部分細(xì)節(jié)自己改了點(diǎn),也加了點(diǎn)自己例子,基本上屬于轉(zhuǎn)載。轉(zhuǎn)載出處:https://my.oschina.net/le...
    洛克黃瓜閱讀 2,115評(píng)論 0 3
  • 在學(xué)習(xí)Python的過程中,我相信有很多人和我一樣,對(duì)Python的裝飾器一直覺得很困惑,我也是困惑了好久,并通過...
    愚灬墨閱讀 506評(píng)論 1 1
  • 一、裝飾器的基本使用 在不改變函數(shù)源代碼的前提下,給函數(shù)添加新的功能,這時(shí)就需要用到“裝飾器”。 0.開放封閉原則...
    NJingZYuan閱讀 623評(píng)論 0 0
  • 好詞: 明晰 光輝 榜樣 謊言 消遣 愛好 光輝 榜樣 謊言 消遣 ...
    清岺閱讀 317評(píng)論 0 0
  • 雖然Fedora 30還沒有上市,F(xiàn)edora 32直到大約一年后才上市,但我們已經(jīng)知道一個(gè)很大的變化:刪除Pyt...
    塵世不擾閱讀 290評(píng)論 0 2

友情鏈接更多精彩內(nèi)容