python3之裝飾器實現 上篇
裝飾器是python中一個強大的功能,利用裝飾器可以在不必改動原有函式的前提下增加一些功能,可以被用於日誌記錄、許可權驗證、除錯測試、事務處理等。裝飾器是閉包的一種形式,閉包是python函式程式設計的高階用法,學習閉包之前讓我們先了解python函式的概念理解和高階用法。本篇文章會結合閉包的形式和使用中的一些注意點分為上下兩篇。
概念理解
<1>變數可以指向函式,函式物件和執行函式的定義
def add(x,y): return x+y fn = add fv = add(3,3) print(add) print(fn) print(fv) print(add(2,3)) print(fn(4,5))
執行結果:
<function add at 0x0000019ED6503840>
<function add at 0x0000019ED6503840>
6
5
9
解析:程式碼<1>中定義了一個add()函式,列印add可以輸出函式物件,列印add()輸出函式執行後的結果。同時變數fn可以指向函式add,通過變數fn()可以呼叫add()函式。變數fv指向了執行函式add(3,3),打印出函式執行後的結果。
python函式高階用法
<1>函式可以作為引數進行傳遞
def add(x, y, f): return f(x) + f(y) print(add(-5, 6, abs))
執行結果
11
<2>函式作為結果值返回
def sum(x,y):
def cal():
return x+y
return cal
f = sum(3,5)
print(f())
執行結果:
8
解析:程式碼<2>中f呼叫執行sum()函式,函式cal物件作為返回值,此時x+y並沒有執行,f()呼叫執行cal()函式,列印計算x+y結果。f呼叫執行sum()函式,同時接收sum()函式的返回值,此時 f=cal
為了說明閉包和巢狀函式的不同,讓我們先看下兩段程式碼,同時引入函式變數作用域的概念。 <1>
x = 0 # 模組級別定義的全域性變數 def outer(): x = 1 # 巢狀中父級函式的區域性作用域變數 def inner(): x = 2 # 函式中定義的變數 print("local: x=",x) inner() print("enclosing: x=",x) outer() print("global: x=",x)
執行結果:
local: x= 2
enclosing: x= 1
global: x= 0
解析:程式碼<1>即平常使用的函式巢狀,python允許出現同名變數,具有相同命名標識的變數在同一函式體中或具有函式巢狀關係,則不同作用域的變數各自代表不同的物件。 如果函式巢狀使用時,內部的inner函式需要傳入引數該如何實現,我們來看接下來的程式碼。 <2>
def outer(x):
def inner(y):
print(x + y)
return inner
f = outer(5)
f(10)
解析:程式碼<2>中函式inner作為結果返回。若呼叫某函式時,該函式將其內部定義的函式作為返回值,則所返回的函式稱為閉包。f呼叫執行outer()函式,同時接收outer()函式的返回值,此時 f=inner,f(10)列印輸出15(5+10=15)
歸納:函式中,誰呼叫執行函式,同時接收執行函式的返回值。閉包的特點在於從外部能向內部的函式傳遞引數。
利用閉包實現裝飾器 <1>示例程式碼
def add(x,y):
return x+y
print(add(2,3))
執行結果:
5
如果此時我們需要在函式執行前打印出函式的引數,又不想改變原來的程式碼,應該怎麼做呢?可以使用裝飾器去實現。 <2>
def decorator(f):
def wrapper(x,y):
print("引數1為:%s,引數2為:%s"%(x,y))
return f(x,y)
return wrapper
@decorator
def add(x,y):
return x+y
print(add(2,3))
執行結果:
5
這種語法結構就是裝飾器,遵循了程式碼編寫的開放封閉原則,即已經實現的功能程式碼不允許被修改,但可以被擴充套件。雖然在這個原則是用的面向物件開發,但是也適用於函數語言程式設計。 關於閉包使用中的注意事項,以及裝飾器的內部原理和高階用法,我們在python之裝飾器下篇介紹。