python函式帶裝飾器 python函式裝飾器

2021-10-11 13:06:12 字數 3445 閱讀 7962

裝飾器(decorators)是python的乙個重要部分。簡單地說:他們是修改其它函式的功能的函式。他們有助於讓我們的**更簡短,也更pythonic。

一切皆物件

我們可以將乙個函式賦值給乙個變數

def hi():

print("hihi")

a=hi

print(a,type(a))

hi() #呼叫hi函式,需要加()

執行結果

在函式中定義函式

def hi():

print("hihi")

def yun():

return "yunyun"

print(yun())

hi()

#yun()#報錯#在hi()函式之外是不能訪問的

執行結果

從函式中返回函式

def hi(name="xx"):

print(name)

def he():

return "xixi"

return he #返回he相當於返回he()函式

a=hi() #此時不會呼叫he(),因為hi()函式中無呼叫此函式的語句

print(a,type(a))

print(a()) #函式呼叫需要加()

執行結果

將函式作為引數傳給另乙個函式

def hi(name="xx"):

print(name)

def study(a):

a()print("我是study")

study(hi)

執行結果

第乙個裝飾器

下面的**你看的懂?都是上面剛剛提到的知識點。

def aa(bb):

print("我是aa哈")

def cc():

print("我是cc吆")

bb()

return "cc"

return cc

def xixi():

print("我是xixi")

m=aa(xixi) #輸出:我是aa哈,

print(m,type(m)) #m是cc()函式

print(m()) #我是cc吆,我是xixi,cc函式的返回值

執行結果

下面我們使用@來修改上面的**

def aa(bb):

print("我是aa哈")

def cc():

print("我是cc吆")

bb()

return "cc"

return cc

@aadef xixi():

print("我是xixi")

print(xixi()) #等價於aa(xixi)()

執行結果

下面存在乙個問題

print(xixi.__name__) #輸出cc

這並不是我們想要的!應該輸出xixi。這裡的函式被cc替代了。它重寫了我們函式的名字和注釋文件(doctring)。幸運的是python提供給我們乙個簡單的函式來解決這個問題,那就是functools.wraps。我們使用functools.wraps修改上乙個例子

from functools import wraps

def aa(bb):

print("我是aa哈")

@wraps(bb)

def cc():

print("我是cc吆")

bb()

return "cc"

return cc

@aadef xixi():

print("我是xixi")

#print(xixi()) #等價於aa(xixi)()

print(xixi.__name__)

執行結果

注意:@wraps接受乙個函式來進行裝飾,並加入了複製函式名稱、注釋文件、引數列表等等的功能。這可以讓我們在裝飾器裡面訪問在裝飾之前的函式的屬性。

藍本規範:

from functools import wraps

def aa(bb):

print("我是aa哈")

@wraps(bb)

def cc(*args,**kwargs):

if not can_run:

return "bb方法不執行"

return bb(*args,**kwargs)

return cc

@aadef xixi():

return "我是xixi"

can_run=false

print(xixi()) #我是aa哈;bb方法不執行;

# can_run=true

# print(xixi()) #我是aa哈;我是xixi

使用場景

授權(authorization)

日誌(logging)

帶引數的裝飾器

來想想這個問題,難道@wraps不也是個裝飾器嗎?但是,它接收乙個引數,就像任何普通的函式能做的那樣。那麼,為什麼我們不也那樣做呢?這是因為,當你使用@aa語法時,你是在應用乙個以單個函式作為引數的乙個包裹函式。記住,python裡每個東西都是乙個物件,而且這包括函式!

在函式中嵌入裝飾器

from functools import wraps

def aa(name="xiaoxiao"):

def bb(cc):

@wraps(cc)

def dd(*args,**kwargs):

log=cc.__name__+"被呼叫"

print(log)

return cc(*args,**kwargs)

return dd

return bb

# @aa() #注意與無參的對比,這裡多了()

# def xixi():

# return "我是xixi"

@aa(name="dehua")

def xixi():

return "我是xixi"

print(xixi()) #xixi被呼叫,我是xixi

執行結果

裝飾器類

沒錯,裝飾器不僅可以是函式,還可以是類,相比函式裝飾器,類裝飾器具有靈活度大、高內聚、封裝性等優點。使用類裝飾器主要依靠類的__call__方法,當使用@形式將裝飾器附加到函式上時,就會呼叫此方法。

class foo(object):

def __init__(self, func):

self._func = func

#print(self._func)

def __call__(self):

print ('class decorator runing')

self._func()

print ('class decorator ending')

@foo

def bar():

print ('bar')

bar()

執行結果

python 帶引數裝飾器

在前面一文 python裡為什麼需要使用裝飾器 decorator 裡,我們學習了為什麼需要裝飾器,知道裝飾器就是為了不修改原來函式的 又達到增加功能的作用。其實為了裝飾器更通用化,那麼裝飾器是否也可以帶引數呢?其實是可以的,這樣更加通用化了,達到共享極點。在前面也學習 為什麼要使用閉包 closu...

無參裝飾器函式和帶參裝飾器函式

python裝飾器 下邊幾個裝飾器帶引數和不帶引數例子詳解 我們都知道,python中函式是可以被當做引數進行傳遞的,所以最直接的裝飾器例項如下 def decorator func 裝飾器函式 print welcome func print end def test print hello wo...

帶函式的裝飾器 多個裝飾器裝飾乙個函式

一 帶引數的裝飾器 開關 author administrator f true defouter f def wap fun ggdef inner args,kwargs iff print inner before ret fun args,kwargs gg print inner afte...