裝飾器
一、定義
1.裝飾者:本質是函數
2.功能:用來裝飾其他函數,為其他函數新增附加功能
二、原則
1.不能修改被裝飾函數的原始碼
2.不能修改被裝飾函數的呼叫方式
三、實作裝飾器
1.函數即變數 的概念
#2.高階函數
##3.巢狀函數>> 高階函數+ 巢狀函數= 裝飾器四、函數即變數1、函數與變數的類比x = 1 print(id(x)) def test(): pass print(test) #输出 1842348496 <function></function>在上例中我們定義了一個變數"x" 和一個函數test(),我們分別列印出變數和函數在記憶體中的位置。可以看出,print(test) 也就是 print("函數名稱")的時候,我們可以列印出函數的記憶體位址。 我們看下面的程式碼:
def test(): print("in the test.") f=test f() #输出 in the test.我們把函數名稱test 賦予給f,然後運行f(),可以看出函數是可以正常運行的,而且就是test函數的運行結果。那麼這和下面的程式碼是不是類似:
x = 1 y = x print(y) #输出 1我們可以做出如下類比,函數名稱 test 相當於 x ,函數體就相當於 1,而 f 就相當於 y。 2.
python中記憶體的表現形式
我們把綠方塊當作是內存,每一個小方塊就是變數或函數在記憶體當中的位址。而變數名稱(x)或函數名稱(test),我們可以形象的將他們比喻為門牌號碼。當需要呼叫變數或函數的時候,我們只要引用他們的門牌號碼就可以找到他們的記憶體位址並返回。只是函數的運算需要加(),如 test()。
既然呼叫變數其實就是引用變數的記憶體位址,而呼叫函數名稱同樣可以得到函數體的記憶體位址。我們就可以把函數名稱當作變數名傳給函數,即函數就是變數。而將函數當作參數的函數,也就是高階函數。 五、高階函數滿足下列條件之一就是高階函數#1.把一個函數名稱當作實參傳給另一個函數2.傳回值包含函數名稱1)函數名稱作為參數
import time def test1(): time.sleep(2) print("in the test1.") def test2(func): start_time = time.time() func() stop_time = time.time() print("The action time of program is {}".format(stop_time-start_time)) test2(test1) #输出 in the test1. The action time of program is 2.0012054443359375以上事例中,我們定義了一個函數test1,同時也定義了一個高階函數test2 。我們把test1函數名稱當作參數傳入test2中,可以實現這樣一個功能,為原本的test1函數增加了一個計算運行時間的功能。這有點像裝飾器了,但是有一點符合,就是上面的高階函數test2改變了函數的呼叫方式。 但是我們實作了在不修改被裝飾函數的基礎上,新增了新功能。 2)傳回值中有函數名稱
def test1(): time.sleep(2) print("in the test1.") def test2(func): print(func) return func test1 = test2(test1) test1() #输出 <function> in the test1.</function>在上例中,我們最後將高階函數test2(test1) 賦予了test1,再次呼叫test1函數。我們可以直觀的看到test1函數的呼叫方式在此例中沒有改變。但是也並沒有增加新功能,而這就需要使用到巢狀函數了。 六、巢狀函數在函數體內又是另一個函數的完整定義,這就是巢狀函數。 1)定義:
def foo(): print("in the foo") def bar(): print("in the bar") bar() foo()僅僅在函數內容呼叫函數,就不是巢狀函數,如下:
def test1(): print("in the test1.") def test2(): test1()2)巢狀函數的作用域
局部作用域和全域作用域的存取順序
x = 0 def grandpa(): x = 1 def dad(): x = 2 def son(): x = 3 print(x) son() dad() grandpa() #输出 33)使用巢狀函數為被修飾函數新增功能 在高階函數第二例中,我們實現了不改變原函數的呼叫方式。而需要加入新功能的話,就要求修飾內容存在在回傳值中,也就是return func 中,我們可以定義一個巢狀函數來實現這個函數。
import time def timer(func): # timer(test1) func = test1 def deco(): start_time = time.time() func() # run test1() stop_time = time.time() print("the action time of the program is {}".format(stop_time-start_time)) return deco # 返回了deco的内存地址 def test1(): time.sleep(2) print("in the test1.") test1 = timer(test1) test1() # 输出 in the test1. the action time of the program is 2.0003786087036133我們在timer()內部定義了一個巢狀函數 deco(),這個巢狀函數實作了為被修飾函數添加運行時間的函數。而timer()函數回傳了deco()的記憶體位址,這個記憶體位址deco就可以被引用,甚至直接賦予給 test1。這樣我們就可以直接執行 test1(),這樣就實作我們的裝飾器的功能。 七、裝飾器 python透過在函數定義前加上一個裝飾器名稱和@符號,來實現對函數的包裝
import time def timer(func): # timer(test1) func = test1 def deco(): start_time = time.time() func() # run test1() stop_time = time.time() print("the action time of the program is {}".format(stop_time-start_time)) return deco # 返回了deco的内存地址 @timer # test1 = timer(test1) def test1(): time.sleep(2) print("in the test1.") test1()
以上是裝飾器decorator詳解及實例的詳細內容。更多資訊請關注PHP中文網其他相關文章!