裝飾器的理解與案例詳解

2021-10-01 16:06:31 字數 4753 閱讀 5068

假設業務部門需要對四個不同功能的函式,增加驗證功能,如何對下列**進行修改?

def

foo1()

:print

("foo1"

)def

foo2()

:print

("foo2"

)def

foo3()

:print

("foo3"

)def

foo4()

:print

("foo4"

)foo1(

)foo2(

)foo3(

)foo4(

)

需要驗證功能,可以寫乙個驗證功能的函式,插入到每乙個功能函式中

# -*- coding:utf-8 -*-

defcheck_foo()

:print

("check"

)def

foo1()

: check_foo(

)print

("foo1"

)def

foo2()

: check_foo(

)print

("foo2"

)def

foo3()

: check_foo(

)print

("foo3"

)def

foo4()

: check_foo(

)print

("foo4"

)foo1(

)foo2(

)foo3(

)foo4(

)

但是,需要了解的是,公司中,老闆一般會要求:對**的修改遵循開放封閉原則,開放-可對**進行擴充套件,封閉-已經實現的**不允許修改。

但是,每個功能**中插入了自己的實現函式,已經進行了修改,沒有滿足老闆的要求。

這時就需要使用python中的裝飾器,它的組成類似於閉包。

擴充套件自己寫的check_foo函式,封裝成乙個裝飾器函式

def

(foo)

:def

check_foo()

:print

("check"

) foo(

)return check_foo

隨後使用@[函式名]在每乙個功能函式上來呼叫裝飾器函式

# -*- coding:utf-8 -*-

deffoo1()

:print

("foo1"

)def

foo2()

:print

("foo2"

)def

foo3()

:print

("foo3"

)def

foo4()

:print

("foo4"

)foo1(

)foo2(

)foo3(

)foo4(

)

執行結果:

check

foo1

check

foo2

check

foo3

check

foo4

後續過程與閉包函式的執行過程一樣

閉包函式的執行過程

例子:

# -*- coding:utf-8 -*-

deffont1

(fn)

:def()

:return

""

+ fn()+

""

deffont2

(fn)

:def()

:return

""+ fn()+

""@font1

defwords1()

:return

"today is a good day!"

@font2

defwords2()

:return

"nothing can change my mind"

@font1

@font2

defwords3()

:return

print

(words1())

print

(words2())

# 將裝飾器font2的結果給裝飾器font1,裝飾器巢狀執行

print

(words3(

))

結果:

today is a good day!<

/b>

nothing can change my mind<

/i>

/i>

<

/b>

從最靠近函式的裝飾器先執行,將執行完成的結果封裝成乙個函式,該函式再向外執行乙個裝飾器,迭代操作,直到完結。

被裝飾的函式的引數會傳入到,內嵌函式中當引數使用

例子:

# -*- coding:utf-8 -*-

from time import ctime, sleep

deftime_foo

(foo)

:def

(a, b)

:print

("%s 被呼叫 %s"

%(foo.__name__, ctime())

)print

(a, b)

foo(a, b)

@time_foo

deffun

(a, b)

:print

(a + b)

fun(1,

3)sleep(2)

fun(5,

7)

結果:

fun 被呼叫 mon dec 2316:

38:58201913

4fun 被呼叫 mon dec 2316:

39:00201957

12

接上面的例子,去掉被裝飾函式以及裝飾器內的引數,再在程式末尾加上乙個speak函式,且不同於fun函式,函式內部是加上return返回值而不是print,但最後的結果不顯示其返回值。

例子:

# -*- coding:utf-8 -*-

from time import ctime, sleep

deftime_foo

(foo)

:def()

:print

("%s 被呼叫 %s"

%(foo.__name__, ctime())

) foo(

)@time_foo

deffun()

:print

("hello"

)@time_foo

defspeak()

:return

"prefect!"

fun(

)speak(

)print

(speak(

))

結果:

fun 被呼叫 mon dec 2316:

55:322019

hello

speak 被呼叫 mon dec 2316:

55:322019

speak 被呼叫 mon dec 2316:

55:322019

none

所以,要列印出被巢狀函式返回值,即,使裝飾器內巢狀函式返回值變為被巢狀函式返回值。

即,修改

foo(

)為return foo(

)

規律:從內到外,第一層函式,引數為被修飾函式引數;第二層函式,引數為被修飾函式的引用;第三層函式,引數為裝飾器引數

# -*- coding:utf-8 -*-

from time import ctime

deftime_foo_param

(fal=

"prefect"):

deftime_inner

(foo)

:def()

:print

("%s called at %s %s"

%(foo.__name__, ctime(

), fal)

)return foo(

) return time_inner

@time_foo_param(

)def

func()

:print

('hello python!'

)func(

)

這裡foo() == time_foo_param()(foo)()

至於前面的雙層巢狀函式,規律同上面總結的一樣,只不過沒有第三層函式,所以無法為裝飾器新增引數,但前兩層所具備的功能都包含。

python裝飾器案例

計算函式的執行時間 import requests import time import re 黑名單 def filter url url 過濾url 測試網路請求的響應時間 def check runtime func print 初始裝飾 func.name 判斷url的 path路徑是否存在...

裝飾器的理解

首先函式是可以呼叫的物件 import time def new print time.time a new a 如果有乙個需求,保證new 不變的情況下,增加new 函式的功能,新增一行輸出等等。在函式執行期間動態增加功能的方式叫做裝飾器decorator 從定義上理解decorator的滿足要素...

Python 裝飾器的理解與示例

coding utf8 import os import pdb 裝飾器的使用場景 和優勢之處在 適用於 乙個功能模組反覆被應用時候 可以 用裝飾器封裝 與其它模組一起 完成特定化的需求 優勢之處 裝飾器 可以不修改之前的 保證業務執行的穩定 增加乙個裝飾器的函式完成新增加的需求 func 放在 被...