一、閉包:
閉包就是內層函數引用了外部函數的變量,然後返回內層函數的情況。閉包的特點就是我們返回的函數,引用了外部函數的局部變量,如果我們希望按照我們所想,來正確的使用這個閉包的話,那就要確定我們引用的局部變量在函數返回以後不能更改。
一個最簡單的閉包:
def outer(arg):
def inner():
return 'Using args:' + arg
return inner
f = outer('hello')
print f()
例如上面的例子,我們定義了一個outer()函數,同時在裏面定義了一個inner()函數。inner()函數使用了outer()中的參數arg,然後我們返回inner函數。所以總的來說,outer函數的返回值是內部定義的inner,同時inner使用了outer()中的參數。
那麼什麼叫外部的參數不能改變呢?
比如,我們定義一個函數getFunc(),這個函數返回了三個函數,分別定義1+1,2+2,3+3
def getFaunc():
L = []
for i in range(1,4):
def f():
return i+i
L.append(f)
return L
f1,f2,f3 = getFaunc()
print f1(),f2(),f3()
結果發現,最後的結果均是3+3。因爲在我們添加完第三個函數的時候,i=3,內部函數使用到的外部參數改變了,所以我們的閉包沒有正確運行
更改爲如下所示:
def getFaunc():
L = []
for i in range(1,4):
def f(i):
def g():
return i+i
return g
tmp = f(i)
L.append(tmp)
return L
f1,f2,f3 = getFaunc()
print f1(),f2(),f3()
區別就是,在第二段代碼中,我們執行了f(i)函數,這就使得相對的g中的變量i固定爲當前f執行時的i,從而不會導致外部的變量改變這種情況
二、Python裝飾器
Python裝飾器,顧名思義就是給函數起到裝飾功能,這就意味着:首先是僅是裝飾而不會更改函數的任何代碼,第二個就是就是增加原有函數的功能。
舉個例子,我們有一個函數是打印當天的日期:
import time
def getDate():
return time.strftime('%Y-%m-%d',time.localtime(time.time()))
print getDate()
如果我們希望在打印日期的時候,在服務器上打印當前的時間,而又不希望更改代碼。這時候就可以使用裝飾器
import time
def getDate():
return time.strftime('%Y-%m-%d',time.localtime(time.time()))
def getDateAndTime(f): # 裝飾器函數,將原函數作爲參數傳入裝飾器函數
def newGetDate(): #在內部聲明一個新函數
print '[SERVER] Current time: '+time.strftime('%H-%M-%S',time.localtime(time.time())) #增加的新功能
return f() # 返回原函數執行
return newGetDate #返回新函數
getDate = getDateAndTime(getDate) #屏蔽掉原有函數
print getDate()
裝飾器看上去很複雜,自底向上拆成以下步驟很好理解:
1. 首先,要屏蔽掉原有函數,將原有函數傳入裝飾器函數,獲得新函數,所以我們需要構造裝飾器函數
2. 在定義的裝飾器函數內部,我們需要定義一個新的函數,擴展功能,並作爲裝飾器函數的返回值
3. 在新函數的內部,擴展新的函數。同時將原函數執行,並作爲 返回值返回。
在python中使用這種方法來實現切面。同時,python提供了@這樣的語法糖,讓我們可很好的使用裝飾器,而不用每次都是使用getDate = getDateAndTime(getDate),來屏蔽原有函數
import time
def getDateAndTime(f):
def newGetDate():
print '[SERVER] Current time: '+time.strftime('%H-%M-%S',time.localtime(time.time()))
return f()
return newGetDate
@getDateAndTime
def getDate():
return time.strftime('%Y-%m-%d',time.localtime(time.time()))
print getDate()
與之前相比,我們只需要將@+裝飾器函數標註在原有函數上,就實現屏蔽原函數的作用。除此之外,python裝飾器也可以帶上參數
import time
def log(arg):
def getDateAndTime(f):
def newGetDate():
print '['+arg+']' +'Current time: '+time.strftime('%H-%M-%S',time.localtime(time.time()))
return f()
return newGetDate
return getDateAndTime
@log('SERVER')
def getDate():
return time.strftime('%Y-%m-%d',time.localtime(time.time()))
print getDate()
在原有的基礎上,多套了一層函數來接收參數。
上面代碼可以解釋爲:
getDateAndTime = log('SERVER')
getDate = getDateAndTime(getDate)
P.S. 文章不妥之處還望指正