因爲Python中,變量做用域爲LEGB,因此在函數內部能夠讀取外部變量,可是在函數外不能讀取函數內的變量。可是出於種種緣由,咱們須要讀取函數內的變量時候怎麼辦?那就是在函數內在加一個函數。javascript
1 def outer(): 2 x = 5 3 def inner(): 4 print(x) 5 return inner 6 7 a = outer() 8 a()#print 5
這樣,咱們就能夠看到函數內部的變量了。html
上面的inner就是閉包,閉包就是可以讀取其餘函數內部變量的函數,也就是定義在函數內部的函數,在本質上來講,閉包就是鏈接函數內和函數外的橋樑。同時,閉包也能夠理解爲能夠攜帶狀態的函數,能夠用這個特性構建相似於類private變量,攜帶狀態的回調函數等。java
閉包有兩大做用,一個是像上面的能夠讀取函數內部的變量,一個是讓這些變量的值始終保存在內存中。閉包
1 def outer(): 2 n = 999 3 def tr(): 4 nonlocal n 5 n = n+1 6 def inner(): 7 print(n) 8 return tr,inner 9 10 tr,a = outer() 11 a()#print999 12 tr() 13 a()#print1000
由於outer爲inner的父函數,而inner被賦值給了一個全局變量,這致使inner和inner依賴的outer常駐內存app
須要注意的是,返回的函數並無立馬執行,直到調用時候纔開始執行。函數
def outer(): acts = [] for i in range(5): acts.append(lambda x:i**x) return acts acts = outer() for i in range(5): print(acts[i](2)) #print #16 #16 #16 #16 #16
輸出爲五個16而不是咱們想要的結果,爲何?性能
就是由於act[i]在內存中一直沒有執行,一直等到調用纔開始執行的,那怎麼辦?學習
方法就是用函數的參數綁定循環變量的值,這樣不管循環變量的值怎麼改變,已經綁定到函數參數的值不會改變spa
1 def outer(): 2 acts = [] 3 for i in range(5): 4 acts.append(lambda x,i=i:i**x) 5 return acts 6 7 acts = outer() 8 for i in range(5): 9 print(acts[i](2)) 10 #print 11 #0 12 #1 13 #4 14 #9 15 #16
使用閉包時候要注意:3d
1)因爲閉包會使得函數中的變量都被保存在內存中,內存消耗很大,因此不能濫用閉包,不然會形成網頁的性能問題,在IE中可能致使內存泄露。解決方法是,在退出函數以前,將不使用的局部變量所有刪除。
2)閉包會在父函數外部,改變父函數內部變量的值。因此,若是你把父函數看成對象(object)使用,把閉包看成它的公用方法(Public Method),把內部變量看成它的私有屬性(private value),這時必定要當心,不要隨便改變父函數內部變量的值。
參考資料:學習javascript閉包
Python學習手冊p431
Python Cookbook