一、閉包概念html
1. 在一個外函數中定義了一個內函數,內函數裏運用了外函數的臨時變量,而且外函數的返回值是內函數的引用,這樣就構成了一個閉包python
2. 通常狀況下,在咱們認知當中,若是一個函數結束,函數的內部全部東西都會釋放掉,還給內存,局部變量都會消失。算法
3. 可是閉包是一種特殊狀況,若是外函數在結束的時候發現有本身的臨時變量未來會在內部函數中用到,就把這個臨時變量綁定給了內部函數,而後本身再結束。數據結構
二、閉包特色 閉包
1. 必須有一個內嵌函數ide
2. 內嵌函數必須引用外部函數中的變量函數
3. 外部函數的返回值必須是內嵌函數spa
#閉包函數的實例 def outer( a ): b = 10 def inner(): # 在內函數中 用到了外函數的臨時變量 print(a+b) # 外函數的返回值是內函數的引用 return inner if __name__ == '__main__': demo = outer(5) demo() # 15 # 在這裏咱們調用外函數傳入參數5 # 此時外函數兩個臨時變量 a是5 b是10 ,並建立了內函數,而後把內函數的引用返回存給了demo # 外函數結束的時候發現內部函數將會用到本身的臨時變量,這兩個臨時變量就不會釋放,會綁定給這個內部函數 # 咱們調用內部函數,看一看內部函數是否是能使用外部函數的臨時變量 # demo存了外函數的返回值,也就是inner函數的引用,這裏至關於執行inner函數
三、閉包中內函數修改外函數局部變量 線程
一、在基本的python語法當中,一個函數能夠隨意讀取全局數據,可是要修改全局數據的時候有兩種方法:
1) global 聲明全局變量
2) 全局變量是可變類型數據的時候能夠修改
二、在閉包狀況下使用下面兩種方法修改
1)在python3中,能夠用nonlocal 關鍵字聲明 一個變量, 表示這個變量不是局部變量空間的變量,須要向上一層變量空間找這個變量。
2)在python2中,沒有nonlocal這個關鍵字,咱們能夠把閉包變量改爲可變類型數據進行修改,好比列表。指針
#修改閉包變量的實例 def outer( a ): b = 10 # a和b都是閉包變量 c = [a] # 這裏對應修改閉包變量的方法2 def inner(): # 方法一: nonlocal關鍵字聲明(python3) nonlocal b b+=1 # 方法二: 把閉包變量修改爲可變數據類型 好比列表(python2) c[0] += 1 print(c[0]) print(b) return inner # 外函數的返回值是內函數的引用 if __name__ == '__main__': demo = outer(5) demo() # 6 11
一、預備知識一——python的變量及其存儲
1. python的一切變量都是對象,變量的存儲,採用了引用語義的方式,存儲的只是一個變量的值所在的內存地址,而不是這個變量的只自己
2. 無論多麼複雜的數據結構,淺拷貝都只會copy一層。
理解:兩我的公用一張桌子,只要桌子不變,桌子上的菜發生了變化兩我的是共同感覺的。
>>> str1 = 'hello' >>> str2 = str1 #一、讓str1和str2變量都存儲了‘hello’所在的內存地址 >>> id(str1) 22748280 >>> id(str1) 22748280 >>> #二、當str1的值變成‘new hello’後str1的值被從新賦值成'new hello'的內存地址,而str2的值依舊是‘hello’的內存地址 >>> str1 = 'new hello' >>> id(str1) 22748320 >>> id(str2) 22748280 #三、無論多麼複雜的數據結構,淺拷貝都只會copy一層。 >>> sourceList = [1,2,[3,4]] >>> newList = sourceList >>> l[2][0]=100 >>> sourceList [1, 2, [100, 4]] >>> newList [1, 2, [100, 4]]
二、淺copy與deepcopy
一、淺copy: 無論多麼複雜的數據結構,淺拷貝都只會copy一層
二、deepcopy : 深拷貝會徹底複製原變量相關的全部數據,在內存中生成一套徹底同樣的內容,咱們對這兩個變量中任意一個修改都不會影響其餘變量
import copy sourceList = [1,2,3,[4,5,6]] copyList = copy.copy(sourceList) deepcopyList = copy.deepcopy(sourceList) sourceList[3][0]=100 print(sourceList) # [1, 2, 3, [100, 5, 6]] print(copyList) # [1, 2, 3, [100, 5, 6]] print(deepcopyList) # [1, 2, 3, [4, 5, 6]]
垃圾回收機制:http://www.javashuo.com/article/p-fqohqhou-ks.html
一、引用計數
1. 原理
1)當一個對象的引用被建立或者複製時,對象的引用計數加1;當一個對象的引用被銷燬時,對象的引用計數減1.
2)當對象的引用計數減小爲0時,就意味着對象已經再沒有被使用了,能夠將其內存釋放掉。
2. 優勢
引用計數有一個很大的優勢,即實時性,任何內存,一旦沒有指向它的引用,就會被當即回收,而其餘的垃圾收集技術必須在某種特殊條件下才能進行無效內存的回收。
3. 缺點
1)引用計數機制所帶來的維護引用計數的額外操做與Python運行中所進行的內存分配和釋放,引用賦值的次數是成正比的,
2)這顯然比其它那些垃圾收集技術所帶來的額外操做只是與待回收的內存數量有關的效率要低。
3)同時,由於對象之間相互引用,每一個對象的引用都不會爲0,因此這些對象所佔用的內存始終都不會被釋放掉。
二、標記-清除
1. 說明
1)它分爲兩個階段:第一階段是標記階段,GC會把全部的活動對象打上標記,第二階段是把那些沒有標記的對象非活動對象進行回收。
2)對象之間經過引用(指針)連在一塊兒,構成一個有向圖
3)從根對象(root object)出發,沿着有向邊遍歷對象,可達的(reachable)對象標記爲活動對象,不可達的對象就是要被清除的非活動對象。
根對象就是全局變量、調用棧、寄存器。
注:像是PyIntObject、PyStringObject這些不可變對象是不可能產生循環引用的,由於它們內部不可能持有其它對象的引用。
1. 在上圖中,能夠從程序變量直接訪問塊1,而且能夠間接訪問塊2和3,程序沒法訪問塊4和5
2. 第一步將標記塊1,並記住塊2和3以供稍後處理。
3. 第二步將標記塊2,第三步將標記塊3,但不記得塊2,由於它已被標記。
4. 掃描階段將忽略塊1,2和3,由於它們已被標記,但會回收塊4和5。
二、缺點
1)標記清除算法做爲Python的輔助垃圾收集技術,主要處理的是一些容器對象,好比list、dict、tuple等
由於對於字符串、數值對象是不可能形成循環引用問題。
2)清除非活動的對象前它必須順序掃描整個堆內存,哪怕只剩下小部分活動對象也要掃描全部對象。
三、分代回收
1. 分代回收是創建在標記清除技術基礎之上的,是一種以空間換時間的操做方式。
2. Python將內存分爲了3「代」,分別爲年輕代(第0代)、中年代(第1代)、老年代(第2代)
3. 他們對應的是3個鏈表,它們的垃圾收集頻率與對象的存活時間的增大而減少。
4. 新建立的對象都會分配在年輕代,年輕代鏈表的總數達到上限時,Python垃圾收集機制就會被觸發
5. 把那些能夠被回收的對象回收掉,而那些不會回收的對象就會被移到中年代去,依此類推
6. 老年代中的對象是存活時間最久的對象,甚至是存活於整個系統的生命週期內。
一、什麼是with語句
1. with是一種上下文管理協議,目的在於從流程圖中把 try,except 和finally 關鍵字和資源分配釋放相關代碼通通去掉,簡化try….except….finlally的處理流程。
2. 因此使用with處理的對象必須有enter()和exit()這兩個方法
1)with經過enter方法初始化(enter方法在語句體執行以前進入運行)
2)而後在exit中作善後以及處理異常(exit()方法在語句體執行完畢退出後運行)
二、with語句使用場景
1. with 語句適用於對資源進行訪問的場合,確保無論使用過程當中是否發生異常都會執行必要的「清理」操做,釋放資源
2. 好比文件使用後自動關閉、線程中鎖的自動獲取和釋放等。
三、with處理文件操做的實例
with open('/etc/passwd') as f: for line in f: print(line)
# 這段代碼的做用:打開一個文件,若是一切正常,把文件對象賦值給f,而後用迭代器遍歷文件中每一行,當完成時,關閉文件;
# 而不管在這段代碼的任何地方,若是發生異常,此時文件仍會被關閉。