您好,登錄后才能下訂單哦!
小編給大家分享一下python中閉包、深淺拷貝、垃圾回收、with語句的示例分析,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!
1.1 閉包
1、閉包概念
1. 在一個外函數(shù)中定義了一個內(nèi)函數(shù),內(nèi)函數(shù)里運用了外函數(shù)的臨時變量,并且外函數(shù)的返回值是內(nèi)函數(shù)的引用,這樣就構(gòu)成了一個閉包
2. 一般情況下,在我們認知當中,如果一個函數(shù)結(jié)束,函數(shù)的內(nèi)部所有東西都會釋放掉,還給內(nèi)存,局部變量都會消失。
3. 但是閉包是一種特殊情況,如果外函數(shù)在結(jié)束的時候發(fā)現(xiàn)有自己的臨時變量將來會在內(nèi)部函數(shù)中用到,就把這個臨時變量綁定給了內(nèi)部函數(shù),然后自己再結(jié)束。
2、閉包特點
1. 必須有一個內(nèi)嵌函數(shù)
2. 內(nèi)嵌函數(shù)必須引用外部函數(shù)中的變量
3. 外部函數(shù)的返回值必須是內(nèi)嵌函數(shù)
#閉包函數(shù)的實例 def outer( a ): b = 10 def inner(): # 在內(nèi)函數(shù)中 用到了外函數(shù)的臨時變量 print(a+b) # 外函數(shù)的返回值是內(nèi)函數(shù)的引用 return inner if __name__ == '__main__': demo = outer(5) demo() # 15 # 在這里我們調(diào)用外函數(shù)傳入?yún)?shù)5 # 此時外函數(shù)兩個臨時變量 a是5 b是10 ,并創(chuàng)建了內(nèi)函數(shù),然后把內(nèi)函數(shù)的引用返回存給了demo # 外函數(shù)結(jié)束的時候發(fā)現(xiàn)內(nèi)部函數(shù)將會用到自己的臨時變量,這兩個臨時變量就不會釋放,會綁定給這個內(nèi)部函數(shù) # 我們調(diào)用內(nèi)部函數(shù),看一看內(nèi)部函數(shù)是不是能使用外部函數(shù)的臨時變量 # demo存了外函數(shù)的返回值,也就是inner函數(shù)的引用,這里相當于執(zhí)行inner函數(shù) 閉包實例
3、閉包中內(nèi)函數(shù)修改外函數(shù)局部變量
1、在基本的python語法當中,一個函數(shù)可以隨意讀取全局數(shù)據(jù),但是要修改全局數(shù)據(jù)的時候有兩種方法:
1) global 聲明全局變量
2) 全局變量是可變類型數(shù)據(jù)的時候可以修改
2、在閉包情況下使用下面兩種方法修改
1)在python3中,可以用nonlocal 關(guān)鍵字聲明 一個變量, 表示這個變量不是局部變量空間的變量,需要向上一層變量空間找這個變量。
2)在python2中,沒有nonlocal這個關(guān)鍵字,我們可以把閉包變量改成可變類型數(shù)據(jù)進行修改,比如列表。
#修改閉包變量的實例 def outer( a ): b = 10 # a和b都是閉包變量 c = [a] # 這里對應修改閉包變量的方法2 def inner(): # 方法一: nonlocal關(guān)鍵字聲明(python3) nonlocal b b+=1 # 方法二: 把閉包變量修改成可變數(shù)據(jù)類型 比如列表(python2) c[0] += 1 print(c[0]) print(b) return inner # 外函數(shù)的返回值是內(nèi)函數(shù)的引用 if __name__ == '__main__': demo = outer(5) demo() # 6 11 閉包中內(nèi)函數(shù)修改外函數(shù)局部變量
1.2 Python里的拷貝
1、預備知識一——python的變量及其存儲
1. python的一切變量都是對象,變量的存儲,采用了引用語義的方式,存儲的只是一個變量的值所在的內(nèi)存地址,而不是這個變量的只本身
2. 不管多么復雜的數(shù)據(jù)結(jié)構(gòu),淺拷貝都只會copy一層。
理解:兩個人公用一張桌子,只要桌子不變,桌子上的菜發(fā)生了變化兩個人是共同感受的。
>>> str1 = 'hello' >>> str2 = str1 #1、讓str1和str2變量都存儲了‘hello'所在的內(nèi)存地址 >>> id(str1) >>> id(str1) >>> #2、當str1的值變成‘new hello'后str1的值被重新賦值成'new hello'的內(nèi)存地址,而str2的值依舊是‘hello'的內(nèi)存地址 >>> str1 = 'new hello' >>> id(str1) >>> id(str2) #3、不管多么復雜的數(shù)據(jù)結(jié)構(gòu),淺拷貝都只會copy一層。 >>> sourceList = [1,2,[3,4]] >>> newList = sourceList >>> l[2][0]=100 >>> sourceList [1, 2, [100, 4]] >>> newList [1, 2, [100, 4]] 不管多么復雜的數(shù)據(jù)結(jié)構(gòu),淺拷貝都只會copy一層
2、淺copy與deepcopy
1、淺copy: 不管多么復雜的數(shù)據(jù)結(jié)構(gòu),淺拷貝都只會copy一層
2、deepcopy : 深拷貝會完全復制原變量相關(guān)的所有數(shù)據(jù),在內(nèi)存中生成一套完全一樣的內(nèi)容,我們對這兩個變量中任意一個修改都不會影響其他變量
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]] 淺copy與deepcopy
1.3 Python垃圾回收機制
垃圾回收機制:https://www.jb51.net/article/168707.htm
1、引用計數(shù)
1. 原理
1)當一個對象的引用被創(chuàng)建或者復制時,對象的引用計數(shù)加1;當一個對象的引用被銷毀時,對象的引用計數(shù)減1.
2)當對象的引用計數(shù)減少為0時,就意味著對象已經(jīng)再沒有被使用了,可以將其內(nèi)存釋放掉。
2. 優(yōu)點
引用計數(shù)有一個很大的優(yōu)點,即實時性,任何內(nèi)存,一旦沒有指向它的引用,就會被立即回收,而其他的垃圾收集技術(shù)必須在某種特殊條件下才能進行無效內(nèi)存的回收。
3. 缺點
1)引用計數(shù)機制所帶來的維護引用計數(shù)的額外操作與Python運行中所進行的內(nèi)存分配和釋放,引用賦值的次數(shù)是成正比的,
2)這顯然比其它那些垃圾收集技術(shù)所帶來的額外操作只是與待回收的內(nèi)存數(shù)量有關(guān)的效率要低。
3)同時,因為對象之間相互引用,每個對象的引用都不會為0,所以這些對象所占用的內(nèi)存始終都不會被釋放掉。
2、標記-清除
1. 說明
1)它分為兩個階段:第一階段是標記階段,GC會把所有的活動對象打上標記,第二階段是把那些沒有標記的對象非活動對象進行回收。
2)對象之間通過引用(指針)連在一起,構(gòu)成一個有向圖
3)從根對象(root object)出發(fā),沿著有向邊遍歷對象,可達的(reachable)對象標記為活動對象,不可達的對象就是要被清除的非活動對象。
根對象就是全局變量、調(diào)用棧、寄存器。
注:像是PyIntObject、PyStringObject這些不可變對象是不可能產(chǎn)生循環(huán)引用的,因為它們內(nèi)部不可能持有其它對象的引用。
1. 在上圖中,可以從程序變量直接訪問塊1,并且可以間接訪問塊2和3,程序無法訪問塊4和5
2. 第一步將標記塊1,并記住塊2和3以供稍后處理。
3. 第二步將標記塊2,第三步將標記塊3,但不記得塊2,因為它已被標記。
4. 掃描階段將忽略塊1,2和3,因為它們已被標記,但會回收塊4和5。
2、缺點
1)標記清除算法作為Python的輔助垃圾收集技術(shù),主要處理的是一些容器對象,比如list、dict、tuple等
因為對于字符串、數(shù)值對象是不可能造成循環(huán)引用問題。
2)清除非活動的對象前它必須順序掃描整個堆內(nèi)存,哪怕只剩下小部分活動對象也要掃描所有對象。
3、分代回收
1. 分代回收是建立在標記清除技術(shù)基礎之上的,是一種以空間換時間的操作方式。
2. Python將內(nèi)存分為了3“代”,分別為年輕代(第0代)、中年代(第1代)、老年代(第2代)
3. 他們對應的是3個鏈表,它們的垃圾收集頻率與對象的存活時間的增大而減小。
4. 新創(chuàng)建的對象都會分配在年輕代,年輕代鏈表的總數(shù)達到上限時,Python垃圾收集機制就會被觸發(fā)
5. 把那些可以被回收的對象回收掉,而那些不會回收的對象就會被移到中年代去,依此類推
6. 老年代中的對象是存活時間最久的對象,甚至是存活于整個系統(tǒng)的生命周期內(nèi)。
1.4 上下文管理(with)
1、什么是with語句
1. with是一種上下文管理協(xié)議,目的在于從流程圖中把 try,except 和finally 關(guān)鍵字和資源分配釋放相關(guān)代碼統(tǒng)統(tǒng)去掉,簡化try….except….finlally的處理流程。
2. 所以使用with處理的對象必須有enter()和exit()這兩個方法
1)with通過enter方法初始化(enter方法在語句體執(zhí)行之前進入運行)
2)然后在exit中做善后以及處理異常(exit()方法在語句體執(zhí)行完畢退出后運行)
2、with語句使用場景
1. with 語句適用于對資源進行訪問的場合,確保不管使用過程中是否發(fā)生異常都會執(zhí)行必要的“清理”操作,釋放資源
2. 比如文件使用后自動關(guān)閉、線程中鎖的自動獲取和釋放等。
3、with處理文件操作的實例
with open('/etc/passwd') as f: for line in f: print(line) # 這段代碼的作用:打開一個文件,如果一切正常,把文件對象賦值給f,然后用迭代器遍歷文件中每一行,當完成時,關(guān)閉文件; # 而無論在這段代碼的任何地方,如果發(fā)生異常,此時文件仍會被關(guān)閉。
看完了這篇文章,相信你對“python中閉包、深淺拷貝、垃圾回收、with語句的示例分析”有了一定的了解,如果想了解更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。