日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > python >内容正文

python

python 的内存回收,及深浅Copy详解

發(fā)布時(shí)間:2023/12/2 python 61 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python 的内存回收,及深浅Copy详解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
一、python中的變量及引用 1.1 python中的不可變類型:

數(shù)字(num)字符串(str)元組(tuple)布爾值(bool<True,False>)
接下來我們講完后你就懂了為什么它們是不可變對(duì)象了。
都知道python中一切都是對(duì)象,而變量就是這些對(duì)象的引用,什么意思呢
綜合表述:
變量是一個(gè)系統(tǒng)表的元素,擁有指向?qū)ο蟮倪B接的空間

對(duì)象是被分配的一塊內(nèi)存,存儲(chǔ)其所代表的值

引用是自動(dòng)形成的從變量到對(duì)象的指針

特別注意: 類型屬于對(duì)象,不是變量

>>> c = 17 #1 數(shù)字17就是一個(gè)對(duì)象,實(shí)實(shí)在在存在計(jì)算機(jī)內(nèi)存中 >>> d = c #2 c 和 d 都是對(duì)象17的一個(gè)引用,c指向17,d也是 >>> id(c) #3 1462698960 >>> id(d) #4 1462698960

在#1 處我們定義了各一個(gè)變量c,c指向了17(把17賦值給c),對(duì)象17的一個(gè)引用c

然后在#2處,又定義了一個(gè)變量d ,把c賦值給了d,接著#3、#4查看了c、d的 id 相同,
發(fā)現(xiàn)是同一個(gè)對(duì)象(17),對(duì)象17的引用+1

引用:
對(duì)象17的引用現(xiàn)在有兩個(gè)了
變量:
在內(nèi)部,變量事實(shí)上是到對(duì)象內(nèi)存空間的一個(gè)指針

1.2 python中內(nèi)存回收機(jī)制
1.2.1 python本身是一門動(dòng)態(tài)語(yǔ)言
與c/c++ /java不同,不需要事先定義變量開辟內(nèi)存空間,然后給變量賦值,存儲(chǔ)到變量的內(nèi)存空間中。使用結(jié)束,當(dāng)然也不需要你去手動(dòng)調(diào)用析構(gòu)函數(shù)釋放內(nèi)存了。
python會(huì)預(yù)先申請(qǐng)一部分內(nèi)存空間,在運(yùn)行時(shí)定義了變量-對(duì)象,根據(jù)對(duì)象確認(rèn)它的type,將對(duì)象放到申請(qǐng)的內(nèi)存中,python每過一段時(shí)間就來檢查一次,當(dāng)有對(duì)象的引用為0時(shí),就回收這塊內(nèi)存,返還回先申請(qǐng)的內(nèi)存空間,而不是計(jì)算機(jī)。這樣避免了內(nèi)存碎片過多問題。

1.2.2 怎么減少對(duì)象的引用

  • 將變量引用指向其他對(duì)象
  • >>> c = 17 >>> d = c >>> id(c) #1 1462698960 >>> id(d) #2 1462698960 >>> c = "yue" #3 >>> id(c) #4 612496081896 >>> d #5 17

    可以看到#1、#2處c、d都還是對(duì)象17的引用,當(dāng)#3處把變量c 指向新對(duì)象字符串"yue" 時(shí),#4處發(fā)現(xiàn)變量c指向的對(duì)象id變了,的確不是17了,所以對(duì)象17的引用 -1 如下圖
    注意:這兒改變了c的引用,可是#5處d卻沒有跟著c變,還是對(duì)象17

    同理當(dāng)你再把d指向其他對(duì)象時(shí),對(duì)象17的引用就減為零,當(dāng)Python來檢查時(shí),就會(huì)回收這塊內(nèi)存了

    2.刪除變量(引用)

    >>> del d >>> d Traceback (most recent call last):File "<stdin>", line 1, in <modul NameError: name 'd' is not defined

    不啰嗦,這樣對(duì)象17就徹底被刪除了,上圖時(shí)對(duì)象17只剩下一個(gè)變量引用d。
    同理對(duì)于函數(shù),定義函數(shù)時(shí),函數(shù)名就是一個(gè)引用,當(dāng)其他地方調(diào)用函數(shù)時(shí),引用+1,調(diào)用結(jié)束 -1 。在函數(shù)的命名空間中可以查到這些,詳情看我這篇文章

    python的內(nèi)存回收就到這兒:總結(jié):回收機(jī)制為判斷對(duì)象 引用是否為0,如果為零就回收內(nèi)存到自己申請(qǐng)的內(nèi)存空間,不是計(jì)算機(jī)硬盤。

    1.3 再談不可變類型

    通過上面的式子和圖理解我們也知道了,當(dāng)定義變量為數(shù)字、字符串、tuple、布爾值時(shí),這些變量所對(duì)應(yīng)的對(duì)象在內(nèi)存空間的值是不可改變了,你重新賦值,也只是把變量引用指向了另一個(gè)對(duì)象,id變了,本身那個(gè)對(duì)象是不可變的。

    >>> a = (1, 'one') >>> id(a) 612494666568 #1 >>> a[0] = 2 Traceback (most recent call last):File "<stdin>", line 1, in <module> TypeError: 'tuple' object does not support item assignment >>> a[0] 1 >>> a = (2, 'two') >>> id(a) 612494666824 #2#--------------------------------------------- >>> a = 'findxgo' #3 >>> id(a) 612496082848 >>> a.replace('x','--X--') #4 'find--X--go' >>> id(a) #5 612496082848 >>> a = a.replace('x', '-X-') #6 >>> id(a) 612496086704

    在#3出定義了字符串a(chǎn),#4處替換x,得到一新字符串,但是原字符串還是#5id沒變,當(dāng)#6把替換的字符串賦值給變量a,a的引用指向了替換后新字符串

    二、python中的深淺Copy 2.1 共享引用

    如圖:指兩個(gè)或多個(gè)變量指向同一個(gè)內(nèi)存空間

    如果刪掉c后, 不會(huì)影響d

    拷貝概念的引入就是針對(duì):可變對(duì)象的共享引用潛在的副作用而提出的。

    2.2 可變對(duì)象

    2.2.1 指python中,存儲(chǔ)在內(nèi)存可以被修改的對(duì)象:列表、字典等
    上面說的數(shù)字、字符串、元組等不可變類型,在你復(fù)制時(shí)也就是增加了一個(gè)引用,無法去改變內(nèi)存的值。對(duì)對(duì)象的其中一個(gè)引用變量操作不會(huì)影響其他引用。
    但是對(duì)于列表、字典:

    >>> list_1 = [5, 2, 1] >>> L2 = list_1 #1 將list_1賦值給L2 >>> list_1,L2 ([5, 2, 1], [5, 2, 1]) >>> list_1[2] = '01314' #2 修改list_1 索引2處的值 >>> list_1,L2 ([5, 2, '01314'], [5, 2, '01314'])

    可以看到#1 上面定義一個(gè)列表,賦值給L2后,L2、list_1對(duì)應(yīng)完全一樣的值(列表)事實(shí)上,他兩的確對(duì)應(yīng)著一塊內(nèi)存,你可以自己去查id,是那塊內(nèi)存(列表)的兩個(gè)引用
    當(dāng)你去在list_1,或者L2進(jìn)行操作時(shí),改變了對(duì)應(yīng)內(nèi)存的值,所以#2下面兩個(gè)值都變了。python中同一塊內(nèi)存(對(duì)象)的不同引用改變對(duì)象所以引用都會(huì)被影響。
    同理字典:通過自己哈希表將key計(jì)算后得到的內(nèi)存地址就是存放value的地方,當(dāng)你用如上同樣的方式改變哪兒的值,所有引用都會(huì)被影響。

    2.3 淺copy

    上述的情況如果想避免,有兩種方式,原理都一樣:copy一份放到另一個(gè)內(nèi)存,變成同樣(value)的兩個(gè)對(duì)象,當(dāng)你修改其中一個(gè)時(shí),另一個(gè)不會(huì)影響。
    1、切片復(fù)制:完全切片

    >>> list_1 = [5, 2, 1] >>> L2 = list_1[:] #1 此處完全切片,復(fù)制 >>> list_1,L2 ([5, 2, 1], [5, 2, 1]) >>> id(list_1) #2 查看id 612496051784 >>> id(L2) #3 612496051720

    如上:#1處完全切片也可以L2 = list_1[0: -1]是一樣的,#2,#3處可以看見,id不同,就不是同一個(gè)對(duì)象,只是里面的value相同而已
    同理copy模塊的copy方法,這是淺拷貝。

    2.4 深copy
  • 深淺拷貝,即可用于序列,也可用于字典
  • >>> import copy>>> dict_1 = {'copy': '淺拷貝', 'deepcopy': ['deep', '第二層', ' 深拷貝']}>>> D2 = copy.copy(dict_1) #淺拷貝:只拷貝頂級(jí)的對(duì)象,也說:父級(jí)對(duì)象>>> D3 = copy.deepcopy(dict_1) #深拷貝:拷貝所有對(duì)象,頂級(jí)對(duì)象及其嵌套對(duì)象。或者說:父級(jí)對(duì)象及其子對(duì)象>>> print("源:{0: ^18}\n淺拷貝:{1}\n深拷貝:{2}".format(id(dict_1),id(D2),id(D3))) 源: 37811303432 淺拷貝:37813197256 深拷貝:37813160264

    2.改變?cè)错敿?jí)對(duì)象,深淺拷貝不會(huì)變

    >>> dict_1['copy'] = 'n_copy' >>> dict_1;D2;D3 {'copy': 'n_copy', 'deepcopy': ['deep', '第二層', ' 深拷貝']} {'copy': '淺拷貝', 'deepcopy': ['deep', '第二層', ' 深拷貝']} {'copy': '淺拷貝', 'deepcopy': ['deep', '第二層', ' 深拷貝']}

    3.改變?cè)辞短讓?duì)象,淺拷貝變了,深拷貝不變

    >>> dict_1['deepcopy'][1] = '嵌套層' >>> dict_1;D2;D3 {'copy': 'n_copy', 'deepcopy': ['deep', '嵌套層', ' 深拷貝']} {'copy': '淺拷貝', 'deepcopy': ['deep', '嵌套層', ' 深拷貝']} {'copy': '淺拷貝', 'deepcopy': ['deep', '第二層', ' 深拷貝']}

    這兒的淺拷貝,只拷貝了父級(jí)對(duì)象,在'deepcopy'對(duì)應(yīng)的哪兒就是只拷貝了內(nèi)存地址,而深拷貝還要去內(nèi)存地址拷貝內(nèi)容回來賦值
    原理看到這兒,差不多也懂了,就不羅嗦了!

    三、總結(jié)
    • 深淺拷貝都是對(duì)源對(duì)象的復(fù)制,占用不同的內(nèi)存空間
    • 如果源對(duì)象只有一級(jí)目錄的話,源做任何改動(dòng),不影響深淺拷貝對(duì)象
    • 如果源對(duì)象不止一級(jí)目錄的話,源做任何改動(dòng),都要影響淺拷貝,但不影響深拷貝
    • 序列對(duì)象的切片其實(shí)是淺拷貝,即只拷貝頂級(jí)的對(duì)象

    一個(gè)有意思的練習(xí)題

    import copy a = [1,2,3,[4,5],6] b=a c=copy.copy(a) d=copy.deepcopy(a) b.append(10) c[3].append(11) d[3].append(12)

    a,b,c,d分別為什么?
    答案我放評(píng)論

    轉(zhuǎn)載于:https://www.cnblogs.com/shiqi17/p/9417663.html

    總結(jié)

    以上是生活随笔為你收集整理的python 的内存回收,及深浅Copy详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。