欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺析Python的對(duì)象拷貝和內(nèi)存布局

 更新時(shí)間:2022年12月18日 14:20:13   作者:一無(wú)是處的研究僧  
這篇文章主要為大家詳細(xì)介紹了Python中的對(duì)象拷貝和內(nèi)存布局的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Python有一定的幫助,需要的可以參考一下

前言

在本篇文章當(dāng)中主要給大家介紹 python 當(dāng)中的拷貝問(wèn)題,話不多說(shuō)我們直接看代碼,你知道下面一些程序片段的輸出結(jié)果嗎?

a?=?[1,?2,?3,?4]
b?=?a
print(f"{a?=?}?\t|\t?{b?=?}")
a[0]?=?100
print(f"{a?=?}?\t|\t?{b?=?}")
a?=?[1,?2,?3,?4]
b?=?a.copy()
print(f"{a?=?}?\t|\t?{b?=?}")
a[0]?=?100
print(f"{a?=?}?\t|\t?{b?=?}")
a?=?[[1,?2,?3],?2,?3,?4]
b?=?a.copy()
print(f"{a?=?}?\t|\t?{b?=?}")
a[0][0]?=?100
print(f"{a?=?}?\t|\t?{b?=?}")
a?=?[[1,?2,?3],?2,?3,?4]
b?=?copy.copy(a)
print(f"{a?=?}?\t|\t?{b?=?}")
a[0][0]?=?100
print(f"{a?=?}?\t|\t?{b?=?}")
a?=?[[1,?2,?3],?2,?3,?4]
b?=?copy.deepcopy(a)
print(f"{a?=?}?\t|\t?{b?=?}")
a[0][0]?=?100
print(f"{a?=?}?\t|\t?{b?=?}")

在本篇文章當(dāng)中我們將對(duì)上面的程序進(jìn)行詳細(xì)的分析。

Python 對(duì)象的內(nèi)存布局

在 python 當(dāng)中我們應(yīng)該如何確定一個(gè)對(duì)象的內(nèi)存地址呢?在 Python 當(dāng)中給我們提供了一個(gè)內(nèi)嵌函數(shù) id() 用于得到一個(gè)對(duì)象的內(nèi)存地址:

a?=?[1,?2,?3,?4]
b?=?a
print(f"{a?=?}?\t|\t?{b?=?}")
a[0]?=?100
print(f"{a?=?}?\t|\t?{b?=?}")
print(f"{id(a)?=?}?\t|\t?{id(b)?=?}")
#?輸出結(jié)果
#?a?=?[1,?2,?3,?4]??|??b?=?[1,?2,?3,?4]
#?a?=?[100,?2,?3,?4]??|??b?=?[100,?2,?3,?4]
#?id(a)?=?4393578112??|??id(b)?=?4393578112

事實(shí)上上面的對(duì)象內(nèi)存布局是有一點(diǎn)問(wèn)題的,或者說(shuō)是不夠準(zhǔn)確的,但是也是能夠表示出各個(gè)對(duì)象之間的關(guān)系的,我們現(xiàn)在來(lái)深入了解一下。在 Cpython 里你可以認(rèn)為每一個(gè)變量都可以認(rèn)為是一個(gè)指針,指向被表示的那個(gè)數(shù)據(jù),這個(gè)指針保存的就是這個(gè) Python 對(duì)象的內(nèi)存地址。

在 Python 當(dāng)中,實(shí)際上列表保存的指向各個(gè) Python 對(duì)象的指針,而不是實(shí)際的數(shù)據(jù),因此上面的一小段代碼,可以用如下的圖表示對(duì)象在內(nèi)存當(dāng)中的布局:

變量 a 指向內(nèi)存當(dāng)中的列表 [1, 2, 3, 4],列表當(dāng)中有 4 個(gè)數(shù)據(jù),這四個(gè)數(shù)據(jù)都是指針,而這四個(gè)指針指向內(nèi)存當(dāng)中 1,2,3,4 這四個(gè)數(shù)據(jù)??赡苣銜?huì)有疑問(wèn),這不是有問(wèn)題嗎?都是整型數(shù)據(jù)為什么不直接在列表當(dāng)中存放整型數(shù)據(jù),為啥還要加一個(gè)指針,再指向這個(gè)數(shù)據(jù)呢?

事實(shí)上在 Python 當(dāng)中,列表當(dāng)中能夠存放任何 Python 對(duì)象,比如下面的程序是合法的:

data?=?[1,?{1:2,?3:4},?{'a',?1,?2,?25.0},?(1,?2,?3),?"hello?world"]

在上面的列表當(dāng)中第一個(gè)到最后一個(gè)數(shù)據(jù)的數(shù)據(jù)類型為:整型數(shù)據(jù),字典,集合,元祖,字符串,現(xiàn)在來(lái)看為了實(shí)現(xiàn)  Python 的這個(gè)特性,指針的特性是不是符合要求呢?每個(gè)指針?biāo)加玫膬?nèi)存是一樣的,因此可以使用一個(gè)數(shù)組去存儲(chǔ) Python 對(duì)象的指針,然后再將這個(gè)指針指向真正的 Python 對(duì)象!

牛刀小試

在經(jīng)過(guò)上面的分析之后,我們來(lái)看一下下面的代碼,他的內(nèi)存布局是什么情況:

data?=?[[1,?2,?3],?4,?5,?6]
data_assign?=?data
data_copy?=?data.copy()

  • data_assign = data,關(guān)于這個(gè)賦值語(yǔ)句的內(nèi)存布局我們?cè)谥耙呀?jīng)談到過(guò)了,不過(guò)我們也再?gòu)?fù)習(xí)一下,這個(gè)賦值語(yǔ)句的含義就是 data_assign 和 data 指向的數(shù)據(jù)是同一個(gè)數(shù)據(jù),也就是同一個(gè)列表。
  • data_copy = data.copy(),這條賦值語(yǔ)句的含義是將 data 指向的數(shù)據(jù)進(jìn)行淺拷貝,然后讓 data_copy 指向拷貝之后的數(shù)據(jù),這里的淺拷貝的意思就是,對(duì)列表當(dāng)中的每一個(gè)指針進(jìn)行拷貝,而不對(duì)列表當(dāng)中指針指向的數(shù)據(jù)進(jìn)行拷貝。從上面的對(duì)象的內(nèi)存布局圖我們可以看到 data_copy 指向一個(gè)新的列表,但是列表當(dāng)中的指針指向的數(shù)據(jù)和 data 列表當(dāng)中的指針指向的數(shù)據(jù)是一樣的,其中 data_copy 使用綠色的箭頭進(jìn)行表示,data 使用黑色的箭頭進(jìn)行表示。

查看對(duì)象的內(nèi)存地址

在前面的文章當(dāng)中我們主要分析了一下對(duì)象的內(nèi)存布局,在本小節(jié)我們使用 python 給我們提供一個(gè)非常有效的工具去驗(yàn)證這一點(diǎn)。在 python 當(dāng)中我們可以使用 id() 去查看對(duì)象的內(nèi)存地址,id(a) 就是查看對(duì)象 a 所指向的對(duì)象的內(nèi)存地址。

看下面的程序的輸出結(jié)果:

a?=?[1,?2,?3]
b?=?a
print(f"{id(a)?=?}?{id(b)?=?}")
for?i?in?range(len(a)):
????print(f"{i?=?}?{id(a[i])?=?}?{id(b[i])?=?}")

根據(jù)我們之前的分析,a 和 b 指向的同一塊內(nèi)存,也就說(shuō)兩個(gè)變量指向的是同一個(gè) Python 對(duì)象,因此上面的多有輸出的 id 結(jié)果 a 和 b 都是相同的,上面的輸出結(jié)果如下:

id(a) = 4392953984 id(b) = 4392953984
i = 0 id(a[i]) = 4312613104 id(b[i]) = 4312613104
i = 1 id(a[i]) = 4312613136 id(b[i]) = 4312613136
i = 2 id(a[i]) = 4312613168 id(b[i]) = 4312613168

看一下淺拷貝的內(nèi)存地址:

a?=?[[1,?2,?3],?4,?5]
b?=?a.copy()
print(f"{id(a)?=?}?{id(b)?=?}")
for?i?in?range(len(a)):
????print(f"{i?=?}?{id(a[i])?=?}?{id(b[i])?=?}")

根據(jù)我們?cè)谇懊娴姆治?,調(diào)用列表本身的 copy 方法是對(duì)列表進(jìn)行淺拷貝,只拷貝列表的指針數(shù)據(jù),并不拷貝列表當(dāng)中指針指向的真正的數(shù)據(jù),因此如果我們對(duì)列表當(dāng)中的數(shù)據(jù)進(jìn)行遍歷得到指向的對(duì)象的地址的話,列表 a 和列表 b 返回的結(jié)果是一樣的,但是和上一個(gè)例子不同的是 a 和 b 指向的列表的本身的地址是不一樣的(因?yàn)檫M(jìn)行了數(shù)據(jù)拷貝,可以參照下面淺拷貝的結(jié)果進(jìn)行理解)。

可以結(jié)合下面的輸出結(jié)果和上面的文字進(jìn)行理解:

id(a)?=?4392953984?id(b)?=?4393050112?#?兩個(gè)對(duì)象的輸出結(jié)果不相等
i?=?0?id(a[i])?=?4393045632?id(b[i])?=?4393045632?#?指向的是同一個(gè)內(nèi)存對(duì)象因此內(nèi)存地址相等?下同
i?=?1?id(a[i])?=?4312613200?id(b[i])?=?4312613200
i?=?2?id(a[i])?=?4312613232?id(b[i])?=?4312613232

copy模塊

在 python 里面有一個(gè)自帶的包 copy ,主要是用于對(duì)象的拷貝,在這個(gè)模塊當(dāng)中主要有兩個(gè)方法 copy.copy(x) 和 copy.deepcopy()。

copy.copy(x) 方法主要是用于淺拷貝,這個(gè)方法的含義對(duì)于列表來(lái)說(shuō)和列表本身的 x.copy() 方法的意義是一樣的,都是進(jìn)行淺拷貝。這個(gè)方法會(huì)構(gòu)造一個(gè)新的 python 對(duì)象并且會(huì)將對(duì)象 x 當(dāng)中所有的數(shù)據(jù)引用(指針)拷貝一份。

copy.deepcopy(x)  這個(gè)方法主要是對(duì)對(duì)象 x 進(jìn)行深拷貝,這里的深拷貝的含義是會(huì)構(gòu)造一個(gè)新的對(duì)象,會(huì)遞歸的查看對(duì)象 x 當(dāng)中的每一個(gè)對(duì)象,如果遞歸查看的對(duì)象是一個(gè)不可變對(duì)象將不會(huì)進(jìn)行拷貝,如果查看到的對(duì)象是可變對(duì)象的話,將重新開辟一塊內(nèi)存空間,將原來(lái)的在對(duì)象 x 當(dāng)中的數(shù)據(jù)拷貝的新的內(nèi)存當(dāng)中。(關(guān)于可變和不可變對(duì)象我們將在下一個(gè)小節(jié)仔細(xì)分析)

根據(jù)上面的分析我們可以知道深拷貝的花費(fèi)是比淺拷貝多的,尤其是當(dāng)一個(gè)對(duì)象當(dāng)中有很多子對(duì)象的時(shí)候,會(huì)花費(fèi)很多時(shí)間和內(nèi)存空間。

對(duì)于 python 對(duì)象來(lái)說(shuō)進(jìn)行深拷貝和淺拷貝的區(qū)別主要在于復(fù)合對(duì)象(對(duì)象當(dāng)中有子對(duì)象,比如說(shuō)列表,元祖、類的實(shí)例等等)。這一點(diǎn)主要是和下一小節(jié)的可變和不可變對(duì)象有關(guān)系。

可變和不可變對(duì)象與對(duì)象拷貝

在 python 當(dāng)中主要有兩大類對(duì)象,可變對(duì)象和不可變對(duì)象,所謂可變對(duì)象就是對(duì)象的內(nèi)容可以發(fā)生改變,不可變對(duì)象就是對(duì)象的內(nèi)容不能夠發(fā)生改變。

  • 可變對(duì)象:比如說(shuō)列表(list),字典(dict),集合(set),字節(jié)數(shù)組(bytearray),類的實(shí)例對(duì)象。
  • 不可變對(duì)象:整型(int),浮點(diǎn)型(float),復(fù)數(shù)(complex),字符串,元祖(tuple),不可變集合(frozenset),字節(jié)(bytes)。

看到這里你可能會(huì)有疑問(wèn)了,整數(shù)和字符串不是可以修改嗎?

a?=?10
a?=?100
a?=?"hello"
a?=?"world"

比如下面的代碼是正確的,并不會(huì)發(fā)生錯(cuò)誤,但是事實(shí)上其實(shí) a 指向的對(duì)象是發(fā)生了變化的,第一個(gè)對(duì)象指向整型或者字符串的時(shí)候,如果重新賦一個(gè)新的不同的整數(shù)或者字符串對(duì)象的話,python 會(huì)創(chuàng)建一個(gè)新的對(duì)象,我們可以使用下面的代碼進(jìn)行驗(yàn)證:

a?=?10
print(f"{id(a)?=?}")
a?=?100
print(f"{id(a)?=?}")
a?=?"hello"
print(f"{id(a)?=?}")
a?=?"world"
print(f"{id(a)?=?}")

上面的程序的輸出結(jié)果如下所示:

id(a) = 4365566480
id(a) = 4365569360
id(a) = 4424109232
id(a) = 4616350128

可以看到的是當(dāng)重新賦值之后變量指向的內(nèi)存對(duì)象是發(fā)生了變化的(因?yàn)閮?nèi)存地址發(fā)生了變化),這就是不可變對(duì)象,雖然可以對(duì)變量重新賦值,但是得到的是一個(gè)新對(duì)象并不是在原來(lái)的對(duì)象上進(jìn)行修改的!

我們現(xiàn)在來(lái)看一下可變對(duì)象列表發(fā)生修改之后內(nèi)存地址是怎么發(fā)生變化的:

data?=?[]
print(f"{id(data)?=?}")
data.append(1)
print(f"{id(data)?=?}")
data.append(1)
print(f"{id(data)?=?}")
data.append(1)
print(f"{id(data)?=?}")
data.append(1)
print(f"{id(data)?=?}")

上面的代碼輸出結(jié)果如下所示:

id(data) = 4614905664
id(data) = 4614905664
id(data) = 4614905664
id(data) = 4614905664
id(data) = 4614905664

從上面的輸出結(jié)果來(lái)看可以知道,當(dāng)我們往列表當(dāng)中加入新的數(shù)據(jù)之后(修改了列表),列表本身的地址并沒(méi)有發(fā)生變化,這就是可變對(duì)象。

我們?cè)谇懊嬲劦搅松羁截惡蜏\拷貝,我們現(xiàn)在來(lái)分析一下下面的代碼:

data?=?[1,?2,?3]
data_copy?=?copy.copy(data)
data_deep?=?copy.deepcopy(data)
print(f"{id(data?)?=?}?|?{id(data_copy)?=?}?|?{id(data_deep)?=?}")
print(f"{id(data[0])?=?}?|?{id(data_copy[0])?=?}?|?{id(data_deep[0])?=?}")
print(f"{id(data[1])?=?}?|?{id(data_copy[1])?=?}?|?{id(data_deep[1])?=?}")
print(f"{id(data[2])?=?}?|?{id(data_copy[2])?=?}?|?{id(data_deep[2])?=?}")

上面的代碼輸出結(jié)果如下所示:

id(data ) = 4620333952 | id(data_copy) = 4619860736 | id(data_deep) = 4621137024
id(data[0]) = 4365566192 | id(data_copy[0]) = 4365566192 | id(data_deep[0]) = 4365566192
id(data[1]) = 4365566224 | id(data_copy[1]) = 4365566224 | id(data_deep[1]) = 4365566224
id(data[2]) = 4365566256 | id(data_copy[2]) = 4365566256 | id(data_deep[2]) = 4365566256

看到這里你肯定會(huì)非常疑惑,為什么深拷貝和淺拷貝指向的內(nèi)存對(duì)象是一樣的呢?前列我們可以理解,因?yàn)闇\拷貝拷貝的是引用,因此他們指向的對(duì)象是同一個(gè),但是為什么深拷貝之后指向的內(nèi)存對(duì)象和淺拷貝也是一樣的呢?這正是因?yàn)榱斜懋?dāng)中的數(shù)據(jù)是整型數(shù)據(jù),他是一個(gè)不可變對(duì)象,如果對(duì) data 或者 data_copy 指向的對(duì)象進(jìn)行修改,那么將會(huì)指向一個(gè)新的對(duì)象并不會(huì)直接修改原來(lái)的對(duì)象,因此對(duì)于不可變對(duì)象其實(shí)是不用開辟一塊新的內(nèi)存空間在重新賦值的,因?yàn)檫@塊內(nèi)存中的對(duì)象是不會(huì)發(fā)生改變的。

我們?cè)賮?lái)看一個(gè)可拷貝的對(duì)象:

data?=?[[1],?[2],?[3]]
data_copy?=?copy.copy(data)
data_deep?=?copy.deepcopy(data)
print(f"{id(data?)?=?}?|?{id(data_copy)?=?}?|?{id(data_deep)?=?}")
print(f"{id(data[0])?=?}?|?{id(data_copy[0])?=?}?|?{id(data_deep[0])?=?}")
print(f"{id(data[1])?=?}?|?{id(data_copy[1])?=?}?|?{id(data_deep[1])?=?}")
print(f"{id(data[2])?=?}?|?{id(data_copy[2])?=?}?|?{id(data_deep[2])?=?}")

上面的代碼輸出結(jié)果如下所示:

id(data ) = 4619403712 | id(data_copy) = 4617239424 | id(data_deep) = 4620032640
id(data[0]) = 4620112640 | id(data_copy[0]) = 4620112640 | id(data_deep[0]) = 4620333952
id(data[1]) = 4619848128 | id(data_copy[1]) = 4619848128 | id(data_deep[1]) = 4621272448
id(data[2]) = 4620473280 | id(data_copy[2]) = 4620473280 | id(data_deep[2]) = 4621275840

從上面程序的輸出結(jié)果我們可以看到,當(dāng)列表當(dāng)中保存的是一個(gè)可變對(duì)象的時(shí)候,如果我們進(jìn)行深拷貝將創(chuàng)建一個(gè)全新的對(duì)象(深拷貝的對(duì)象內(nèi)存地址和淺拷貝的不一樣)。

代碼片段分析

經(jīng)過(guò)上面的學(xué)習(xí)對(duì)于在本篇文章開頭提出的問(wèn)題對(duì)于你來(lái)說(shuō)應(yīng)該是很簡(jiǎn)單的,我們現(xiàn)在來(lái)分析一下這幾個(gè)代碼片段:

a?=?[1,?2,?3,?4]
b?=?a
print(f"{a?=?}?\t|\t?{b?=?}")
a[0]?=?100
print(f"{a?=?}?\t|\t?{b?=?}")

這個(gè)很簡(jiǎn)單啦,a 和 b 不同的變量指向同一個(gè)列表,a 中間的數(shù)據(jù)發(fā)生變化,那么 b 的數(shù)據(jù)也會(huì)發(fā)生變化,輸出結(jié)果如下所示:

a = [1, 2, 3, 4]  |  b = [1, 2, 3, 4]
a = [100, 2, 3, 4]  |  b = [100, 2, 3, 4]
id(a) = 4614458816  |  id(b) = 4614458816

我們?cè)賮?lái)看一下第二個(gè)代碼片段

a?=?[1,?2,?3,?4]
b?=?a.copy()
print(f"{a?=?}?\t|\t?{b?=?}")
a[0]?=?100
print(f"{a?=?}?\t|\t?{b?=?}")

因?yàn)?b 是 a 的一個(gè)淺拷貝,所以 a 和 b 指向的是不同的列表,但是列表當(dāng)中數(shù)據(jù)的指向是相同的,但是由于整型數(shù)據(jù)是不可變數(shù)據(jù),當(dāng)a[0] 發(fā)生變化的時(shí)候,并不會(huì)修改原來(lái)的數(shù)據(jù),而是會(huì)在內(nèi)存當(dāng)中創(chuàng)建一個(gè)新的整型數(shù)據(jù),因此列表 b 的內(nèi)容并不會(huì)發(fā)生變化。因此上面的代碼輸出結(jié)果如下所示:

a?=?[1,?2,?3,?4]??|??b?=?[1,?2,?3,?4]
a?=?[100,?2,?3,?4]??|??b?=?[1,?2,?3,?4]

再來(lái)看一下第三個(gè)片段:

a?=?[[1,?2,?3],?2,?3,?4]
b?=?a.copy()
print(f"{a?=?}?\t|\t?{b?=?}")
a[0][0]?=?100
print(f"{a?=?}?\t|\t?{b?=?}")

這個(gè)和第二個(gè)片段的分析是相似的,但是 a[0] 是一個(gè)可變對(duì)象,因此進(jìn)行數(shù)據(jù)修改的時(shí)候,a[0] 的指向沒(méi)有發(fā)生變化,因此 a 修改的內(nèi)容會(huì)影響 b。

a?=?[[1,?2,?3],?2,?3,?4]??|??b?=?[[1,?2,?3],?2,?3,?4]
a?=?[[100,?2,?3],?2,?3,?4]??|??b?=?[[100,?2,?3],?2,?3,?4]

最后一個(gè)片段:

a?=?[[1,?2,?3],?2,?3,?4]
b?=?copy.deepcopy(a)
print(f"{a?=?}?\t|\t?{b?=?}")
a[0][0]?=?100
print(f"{a?=?}?\t|\t?{b?=?}")

深拷貝會(huì)在內(nèi)存當(dāng)中重新創(chuàng)建一個(gè)和a[0]相同的對(duì)象,并且讓 b[0] 指向這個(gè)對(duì)象,因此修改 a[0],并不會(huì)影響 b[0],因此輸出結(jié)果如下所示:

a?=?[[1,?2,?3],?2,?3,?4]??|??b?=?[[1,?2,?3],?2,?3,?4]
a?=?[[100,?2,?3],?2,?3,?4]??|??b?=?[[1,?2,?3],?2,?3,?4]

撕開 Python 對(duì)象的神秘面紗

我們現(xiàn)在簡(jiǎn)要看一下 Cpython 是如何實(shí)現(xiàn) list 數(shù)據(jù)結(jié)構(gòu)的,在 list 當(dāng)中到底定義了一些什么東西:

typedef?struct?{
????PyObject_VAR_HEAD
????/*?Vector?of?pointers?to?list?elements.??list[0]?is?ob_item[0],?etc.?*/
????PyObject?**ob_item;

????/*?ob_item?contains?space?for?'allocated'?elements.??The?number
?????*?currently?in?use?is?ob_size.
?????*?Invariants:
?????*?????0?<=?ob_size?<=?allocated
?????*?????len(list)?==?ob_size
?????*?????ob_item?==?NULL?implies?ob_size?==?allocated?==?0
?????*?list.sort()?temporarily?sets?allocated?to?-1?to?detect?mutations.
?????*
?????*?Items?must?normally?not?be?NULL,?except?during?construction?when
?????*?the?list?is?not?yet?visible?outside?the?function?that?builds?it.
?????*/
????Py_ssize_t?allocated;
}?PyListObject;

在上面定義的結(jié)構(gòu)體當(dāng)中 :

allocated 表示分配的內(nèi)存空間的數(shù)量,也就是能夠存儲(chǔ)指針的數(shù)量,當(dāng)所有的空間用完之后需要再次申請(qǐng)內(nèi)存空間。

ob_item 指向內(nèi)存當(dāng)中真正存儲(chǔ)指向 python 對(duì)象指針的數(shù)組,比如說(shuō)我們想得到列表當(dāng)中第一個(gè)對(duì)象的指針的話就是 list->ob_item[0],如果要得到真正的數(shù)據(jù)的話就是 *(list->ob_item[0])。

PyObject_VAR_HEAD 是一個(gè)宏,會(huì)在結(jié)構(gòu)體當(dāng)中定一個(gè)子結(jié)構(gòu)體,這個(gè)子結(jié)構(gòu)體的定義如下:

typedef?struct?{
????PyObject?ob_base;
????Py_ssize_t?ob_size;?/*?Number?of?items?in?variable?part?*/
}?PyVarObject;

這里我們不去談對(duì)象 PyObject 了,主要說(shuō)一下 ob_size,他表示列表當(dāng)中存儲(chǔ)了多少個(gè)數(shù)據(jù),這個(gè)和 allocated 不一樣,allocated 表示 ob_item 指向的數(shù)組一共有多少個(gè)空間,ob_size 表示這個(gè)數(shù)組存儲(chǔ)了多少個(gè)數(shù)據(jù) ob_size <= allocated。

在了解列表的結(jié)構(gòu)體之后我們現(xiàn)在應(yīng)該能夠理解之前的內(nèi)存布局了,所有的列表并不存儲(chǔ)真正的數(shù)據(jù)而是存儲(chǔ)指向這些數(shù)據(jù)的指針。

總結(jié)

在本篇文章當(dāng)中主要給大家介紹了 python 當(dāng)中對(duì)象的拷貝和內(nèi)存布局,以及對(duì)對(duì)象內(nèi)存地址的驗(yàn)證,最后稍微介紹了一下 cpython 內(nèi)部實(shí)現(xiàn)列表的結(jié)構(gòu)體,幫助大家深入理解列表對(duì)象的內(nèi)存布局。

到此這篇關(guān)于淺析Python的對(duì)象拷貝和內(nèi)存布局的文章就介紹到這了,更多相關(guān)Python對(duì)象拷貝 內(nèi)存布局內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論