如何理解Python裝飾器?

時間 2021-05-07 07:22:27

1樓:

這是我見過的最好的Python裝飾器教學文章:

Primer on Python Decorators – Real Python

2樓:

假設我們有乙個 decorator

defcount_time

(name

):def

decorator

(func

):def(*

arg,

**kw

):start

=time

.time

()func(*

arg,

**kw

)print(f

"< end in s >"

)return

return

decorator

我們可以這樣呼叫它

@count_time

("test1"

)def

test_decorator1

():time

.sleep

(1.14514

)test_decorator1

()也可以這樣呼叫它

deftest_decorator2

():func

=lambdax:

time

.sleep(x

)count_time

("test2"

)(func

)(1.14514

)test_decorator2

()都能使其正常發揮作用

< test1 end in 1.1463046073913574s >

< test2 end in 1.1463449001312256s >

而如果 decorator 是長這樣的

defw1

():def

w2():

defw3

():def

w4():

defcount_time

(name

):def

decorator

(func

):def(*

arg,

**kw

):start

=time

.time

()func(*

arg,

**kw

)print(f

"< end in s >"

)return

return

decorator

return

count_time

return

w4return

w3return

w2我們則需要這樣呼叫它

decorator=w1

()()()()(

"test1"

)@decorator

deftest_decorator1

():time

.sleep

(1.14514

)test_decorator1

()或者這樣呼叫它

deftest_decorator2

():func

=lambdax:

time

.sleep(x

)w1()()()()(

"test2"

)(func

)(1.14514

)test_decorator2

()注意這樣呼叫它不行

@w1()()()()(

"test1"

)def

test_decorator1

():time

.sleep

(1.14514

)test_decorator1

()會報錯

@w134;test3"SyntaxError: invalid syntax

結論就是,呼叫被裝飾的函式 func

@decorator

deffunc(*

arg,

**kw

):pass

func(*

arg,

**kw

)等價於先呼叫裝飾器 decorator 函式,以 func 作為引數,得到乙個返回值,這個返回值是乙個函式,再以 func 的引數作為引數呼叫這個返回的函式,得到最終結果f=

decorator

(func

)# 第一步f(

*arg,**

kw)# 第二步

合起來就是

decorator

(func)(*

arg,

**kw

)對於前面的第一種情況,count_time(name) 能夠返回乙個 decorator 函式,所以是

count_time

("test2"

)(func

)(1.14514

)# count_time("test2") | (func)(1.14514)

對於前面的第二種情況,w134;test1") 能夠返回乙個 decorator 函式,所以是

w1()()()()(

"test2"

)(func

)(1.14514

)# w134;test2") | (func)(1.14514)

本質上就是函式的套娃式返回,乙個 () 代表取乙個函式的返回值,@ 語法糖的作用就是幫你省掉最後的兩個括號。。。

3樓:qzylalala

建議看cs61A 斯坦福講SICP的,用的語言是Python。講了higher-order function之後馬上介紹decorator,很nice

4樓:迦侖

Python裝飾器,其實要點只有三個

輸入接受函式作為引數

結果返回函式

利用引數解包和引數傳遞,完成對函式執行前/後的處理工作理解這三點後,我保證你半夜被喊醒,都能徒手寫乙個裝飾器( ˙˙ )ps: Python是一門設計很精巧的語言,直接了當去理解其設計及其使用場景,比看那些長篇大論人生感悟好消化。

加油( _)

5樓:小蔥拌臭豆腐

我覺得裝飾器的使用形象地說就是大臣扶持太子登上皇位的過程。

現在有乙個太子,他只能穿龍袍,不能發布聖旨皇帝老兒就快要駕崩了,太子的心腹大臣一心想要扶持它太子接收皇位公升級為皇帝

獲得新功能

太子為了感謝大臣,把大臣放在頭頂,以示尊敬,就有了語法糖扯不下去了,溜~~~~~~~

6樓:bemyself24

我理解的python修飾器他的輸入是乙個函式,首先你定義一下你修飾器所實現的功能,只不過這時候,你的輸入不再是簡單的各種型別的變數,而是乙個函式,返回的也是乙個函式。很簡單的舉個例子,有時候我們在跑模型的時候,需要知道模型訓練到哪一步了,這時候我們可能是如下的寫法

使用修飾器就變成這樣了

當然,還有其他的一切功能,目前能演示的就這麼多了

7樓:morty

blog.csdn.net/u013471155/article/details/68960244這篇文章寫的很好

很好理解

8樓:天青色等煙雨

乙個函式Login是執行登陸功能的,但是在登陸前要做驗證,比如使用者名稱,密碼不能為空,密碼長度不能低於6位。這個時候我不將驗證邏輯直接寫在Login函式裡,而通過裝飾器去解決這個問題。

defcheck

(func

):def

inner

():print

("驗證好了使用者名稱密碼不能為空了"

)print

("驗證好密碼長度正確了"

)return

func

()return

inner

@check

deflogin

():print

("我要開始登陸拉~"

)return

"登入成功"

if__name__

=='__main__'

:print

(login

())print

("login.__name__:"

,login

.__name__

)在原有的login函式上加了乙個@check,就是給Login新增了乙個裝飾器,這個時候會將@check下的函式作為check函式的引數,並執行check(func)函式。

check裡又定義了乙個inner函式,這個函式裡做了驗證操作,並返回func(特別注意:return func(),返回的時候執行了func,也就是執行了Login函式), 在check函式再把inner函式作為返回值。

所以給Login新增乙個裝飾器的結果是, 裝飾器裡有乙個inner函式,這個inner函式會執行驗證邏輯+返回執行Login函式得到的返回結果。

把上面的結果再再簡化一下,給login新增裝飾器後,呼叫login函式,其實是呼叫check裡的inner函式。看執行print("login.__name__:

",login.__name__)輸出結果。

9樓:薛偉超

雖然是程式設計新手,也嘗試來答乙個,選自我的部落格

在不同語境下,裝飾器有不一樣的含義,我大致認為有3種定義:

一種把另乙個物件當引數的物件

一種語法糖

面對物件設計中的裝飾器模式

之所以這裡特別指出,是因為在很多文章和書中

把裝飾器定義成乙個函式,有些更擴充套件一些,把裝飾器定義成乙個callable物件

對剛開始學習的讀者來說這麼解釋或許不錯,但在使用python的過程中,我們發現裝飾器可以是

函式類 (例: classmethod和property)

類方法 (例: FLask類的route)

如果說類方法有__call__方法,能符合上面callable物件的定義的話

classmethod類和property類可沒__call__方法,所以我認為更準確的定義是我上面說的第1,2點

廣義上說,更優雅地處理物件,相比taget = decorate(target),@decorate可要優雅多了

狹義上說,各種功能:

禁止函式執行 (剛想到,寫個不return原函式的裝飾器去裝飾某函式,這個函式不就不執行了嘛,不曉得是否有人會這麼幹)

記錄函式的執行狀況

快取計算結果

檢查/修改引數

裝逼?其他

10樓:2gua

我覺得我這篇講的還算可以理解,供參考:https://zhuanlan /p/21696291

這一篇 https://

zhuanlan /p/23064109

11樓:xlzd

簡單來講,可以不嚴謹地把Python的裝飾器看做乙個包裝函式的函式。

比如,有乙個函式:

deffunc

():print

'func() run.'

if'__main__'

==__name__

:func

()執行後將輸出:

func() run.

現在需要在函式執行前後列印一條日誌, 但是又不希望或者沒有許可權修改函式內部的結構, 就可以用到裝飾器(decorator):

deflog

(function

):def(*

args,**

kwargs

):print

'before function [

%s()] run.'

%function

.__name__

rst=

function(*

args,**

kwargs

)print

'after function [

%s()] run.'

%function

.__name__

return

rstreturn

@log

deffunc

():print

'func() run.'

if'__main__'

==__name__

:func

()對於原來的函式"func()"並沒有做修改,而是給其使用了裝飾器log,執行後的輸出為:

before

function

[func

()]run

.func

()run

.after

function

[func

()]run

.把"@log"放到func()函式定義的地方,相當於執行了如下語句:

func

=log

(func

)'before function [%s()] run.' % function.__name__

(在Python中函式也是物件,函式的__name__是它的名字),然後執行了原來的函式並記錄了返回值,在輸出

'after function [%s()] run.' % function.__name__

後返回了函式的執行結果。

如果decorator本身需要傳入引數,那就需要編寫乙個返回decorator的decorator。比如在Flask中:

def index():

return 'hello, world!'

實現如下:

import

functools

deflog

(text=''

):def

decorator

(function

):@functools.wraps

(function

)def(*

args,**

kwargs

):print

'before function [

%s()] run, text: [

%s].'%(

function

.__name__

,text

)rst

=function(*

args,**

kwargs

)print

'after function [

%s()] run, text: [

%s].'%(

function

.__name__

,text

)return

rstreturn

return

decorator

@log

('log text'

)def

func

():print

'func() run.'

if'__main__'

==__name__

:func

()輸出如下:

before function [func()] run, text: [log text].

func() run.

after function [func()] run, text: [log text].

最後腦洞小開一下, 有沒有辦法實現既支援不帶引數(如log), 又支援帶引數(如log('text'))的decorator嗎?

import

functools

deflog

(argument

):if

notcallable

(argument

):def

decorator

(function

):@functools.wraps

(function

)def(*

args,**

kwargs

):print

'before function [

%s()] run, text: [

%s].'%(

function

.__name__

,text

)rst

=function(*

args,**

kwargs

)print

'after function [

%s()] run, text: [

%s].'%(

function

.__name__

,text

)return

rstreturn

return

decorator

def(

*args,**

kwargs

):print

'before function [

%s()] run.'

%function

.__name__

rst=

argument(*

args,**

kwargs

)print

'after function [

%s()] run.'

%function

.__name__

return

rstreturn

如上~~~

如何理解python的描述器和裝飾器?

秦仲子 好傢伙,這一堆答案就沒個簡單明瞭的,讓我來。1.裝飾器 有個裝飾器函式funcA,有個被裝飾的函式funcB,如果用funcA裝飾funcB,那麼後續的呼叫時funcB執行效果就funcA funcB python用 符號完成了裝飾器模式,很好的遵循了開閉原則,應用於授權,日誌等場景,還實現...

什麼時候會用到python裝飾器?

decorator factory from functools import wraps defmax result threshold def decorator func wraps func def args,kwargs result func args,kwargs if result ...

為什麼python的裝飾器要雙層巢狀?

無名 努力寫個簡短而又通俗的回答!decorator defmy func 等價於 defmy func my func decorator my func 可見裝飾器是乙個函式,它的input是原函式,output是裝飾後的函式。在裝飾器裡,基於原函式,構造出乙個新函式,看起來就像是雙層巢狀。de...