乙個函式被定義完成後,甚至程式發布後,後期可能需要新增某些功能,但是我們不可能每次都去修改原函式的**,這時候裝飾器就可以上場了,本篇文章將會用乙個個可實現的**,由淺入深、循序漸進得闡述裝飾器的強大之處
裝飾器定義、作用、原則:
定義:乙個裝飾函式的函式,即為其他函式新增附加功能
作用:給函式新增新功能,但是原來的函式**不會被更改
原則:不修改被修飾函式的源**,不修改被修飾函式的呼叫方式
裝飾器=高階函式+函式巢狀+閉包
高階函式:函式接收的引數是乙個函式名 或者 函式的返回值是乙個函式名
未使用裝飾器:
import time
deftest
(s):
start_time = time.time(
) res =
0for i in s:
time.sleep(
0.1)
#沉睡10秒
res += i
stop_time = time.time(
)print
('函式的執行時間是{}秒'
.format
(stop_time - start_time)
)return res
print
(test(
range
(100))
)#執行函式,傳入乙個從0到100的範圍
執行結果:
函式的執行時間是10.012572765350342秒
4950
高階函式:
import time
deffoo()
: time.sleep(3)
print
('大海如此寬廣,總有一天你會遇見真心的夥伴'
)def
test
(func)
:#傳入的引數是乙個函式,即為高階函式
print
(func)
#輸出函式的記憶體位址
func(
)#呼叫形參函式
test(foo)
#呼叫高階函式
執行結果:
大海如此寬廣,總有一天你會遇見真心的夥伴
帶修飾的高階函式(不修改原函式源**):
import time
deffoo()
: time.sleep(3)
print
('大海如此寬廣,總有一天你會遇見真心的夥伴'
)def
test
(func)
:#傳入的引數是乙個函式,即為高階函式
start_time = time.time(
)print
(func)
#輸出函式的記憶體位址
func(
)#呼叫形參函式
stop_time = time.time(
)print
('函式執行時間為 %s'
%(stop_time - start_time)
)test(foo)
#呼叫高階函式
執行結果:
大海如此寬廣,總有一天你會遇見真心的夥伴
函式執行時間為 3.0281732082366943
帶修飾的高階函式(不修改原函式呼叫方式):
import time
deffoo()
: time.sleep(3)
print
('大海如此寬廣,總有一天你會遇見真心的夥伴'
)def
test
(func)
:#傳入的引數是乙個函式,即為高階函式
return func #函式的返回值為函式名,也稱為高階函式
foo = test(foo)
#用foo接收test執行的返回值
foo(
)
執行結果:
大海如此寬廣,總有一天你會遇見真心的夥伴
不修改源**也不修改呼叫方式:
import time
deffoo()
: time.sleep(3)
print
('大海如此寬廣,總有一天你會遇見真心的夥伴'
)def
timmer
(func)
:#作為乙個修飾函式
start_time = time.time(
) func(
) stop_time = time.time(
)print
('函式執行時間為 %s'
%(stop_time - start_time)
)return func #函式的返回值為函式名,也稱為高階函式
foo = timmer(foo)
#將原函式名作為接收的變數,被修飾後,就不會修改原函式的呼叫方式
foo(
)#這樣呼叫後,其實是會連帶被修飾的結果一起輸出,因為上一句賦值時已經呼叫了修飾函式
執行結果:
大海如此寬廣,總有一天你會遇見真心的夥伴
函式執行時間為 3.018172264099121
大海如此寬廣,總有一天你會遇見真心的夥伴
但是這樣,它僅僅用了高階函式,還是滿足不了裝飾器的功能,因為它多執行了一步
函式巢狀:
乙個函式裡定義多個函式(這裡需要用到函式作用域和函式巢狀的知識,在我的這篇文章裡有從淺入深的詳細分析:初學者python筆記(函式))
def
father
(name)
:#name = '白鬍子_1' #三個地方對區域性變數的修改
defson()
:#name = '白鬍子_2'
defgrandson()
:#name = '白鬍子_3'
print
('我的老爹是{}'
.format
(name)
)#離它最近的區域性變數的修改
grandson(
) son(
)#執行巢狀函式
father(
'白鬍子'
)#裡面的變數是乙個乙個層級的關係,從形參,可以一直傳到底層的函式中再呼叫
執行結果:
我的老爹是白鬍子
基本裝飾器的實現(帶語法糖):
import time
deftimmer
(func)
:def
wrap()
: start_time = time.time(
)#給裝飾器加的功能
func(
)#在裝飾器中執行函式
stop_time = time.time(
)print
('函式執行了{}秒'
.format
(stop_time - start_time)
)return wrap #函式的返回值是函式,所以為高階函式
@timmer #語法糖的使用,使原函式即foo函式被裝飾。相當於foo = timmer(foo)語句
deffoo()
: time.sleep(3)
print
('test函式執行完畢!'
)
foo(
)#執行原函式,方式不變,滿足原則
執行結果:
test函式執行完畢!
函式執行了3.0251729488372803秒
能得到原函式返回值的裝飾器:
import time
deftimmer
(func)
:def
wrap()
: start_time = time.time(
)#給裝飾器加的功能
res = func(
)#在裝飾器中執行函式,並且用乙個變數來接收以返回原函式的返回值
stop_time = time.time(
)print
('函式執行了{}秒'
.format
(stop_time - start_time)
)return res #返回原函式的返回值
return wrap #函式的返回值是函式,所以為高階函式
@timmer #語法糖的使用,使原函式即foo函式被裝飾。相當於foo = timmer(foo)語句
deffoo()
: time.sleep(3)
print
('test函式執行完畢!'
)return
'這是test的返回值'
#為了實現把原函式的返回值也接收到
foo(
)#執行原函式,方式不變,滿足原則
print
(foo())
#輸出原函式的返回值
執行結果:
test函式執行完畢!
函式執行了3.0211730003356934秒
test函式執行完畢!
函式執行了3.0581750869750977秒
這是test的返回值
初學者python筆記(裝飾器後篇 登陸驗證)
被修飾的函式引數個數是不固定的,而要修改引數個數就肯定需要修改裝飾器和原函式,違反了裝飾器的修改原函式源 的原則。而基本裝飾器本來是不帶有引數的,如果呼叫原函式需要傳入引數怎麼辦?可以如下操作 裝飾器 import time deftimmer func def wrap args,kwargs 乙...
適合初學者的Python裝飾器簡易教程
裝飾器是python程式語言中相當高階的一部分。就像大多數事情一樣,一旦你掌握了它們的工作原理並使用了幾次,它們就會變得非常簡單明瞭,但是作為乙個初學者,它們可能會有點讓人望而生畏,很難理解。只有理解了它所解決的問題,你才能真正理解它。例如,我可以直接宣告裝飾器的定義 decorator是乙個函式,...
python 初學者計算器
神獸保佑 考試及格!from tkinter import class calc definit self self.num1 self.num2 self.結果 self.顯示內容 self.輸入開關 true self.運算符號 0 self.載入視窗 def 輸入數字 self,數字 if s...