初學者python筆記(裝飾器 高階函式 閉包)

2021-10-03 13:37:47 字數 4828 閱讀 4457

乙個函式被定義完成後,甚至程式發布後,後期可能需要新增某些功能,但是我們不可能每次都去修改原函式的**,這時候裝飾器就可以上場了,本篇文章將會用乙個個可實現的**,由淺入深、循序漸進得闡述裝飾器的強大之處

裝飾器定義、作用、原則:

定義:乙個裝飾函式的函式,即為其他函式新增附加功能

作用:給函式新增新功能,但是原來的函式**不會被更改

原則:不修改被修飾函式的源**,不修改被修飾函式的呼叫方式

裝飾器=高階函式+函式巢狀+閉包

高階函式:函式接收的引數是乙個函式名 或者 函式的返回值是乙個函式名

未使用裝飾器:

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...