陜西省咸陽(yáng)市建設(shè)銀行網(wǎng)站競(jìng)價(jià)推廣托管服務(wù)
前言
再說(shuō)正文之前,需要大家先了解一下對(duì)象,指針和引用的含義,不懂得同學(xué)可以參考我上一篇博客“(12條消息) 引用是否有地址的討論的_xx_xjm的博客-CSDN博客”
正文
一:python中一切皆對(duì)象
? ? ? “python中一切皆對(duì)象”這句話我相信凡是接觸過(guò)python得同學(xué)應(yīng)該都聽(tīng)過(guò),但我想應(yīng)該很少有人真正理解這句話,對(duì)此,本文在這里進(jìn)行一個(gè)簡(jiǎn)單得闡述!
? ? ? ?在C++里面,我們說(shuō)int a = 1; a就是一個(gè)對(duì)象,什么意思呢?在這里a代表了一個(gè)內(nèi)存空間,我們假定這個(gè)內(nèi)存空間的地址是x0001,那么a表示的是存放有1的x0001這個(gè)內(nèi)存空間!所以,與其說(shuō)a是一個(gè)對(duì)象,不如說(shuō)是這個(gè)x0001是個(gè)對(duì)象。a和x0001的關(guān)系就是一個(gè)人和身份證上名字之間的關(guān)系,x0001就表示真實(shí)的人,a表示這個(gè)人身份證上的名字,比如“小明”。所以,我們簡(jiǎn)單理解一下,對(duì)象,就是一個(gè)真實(shí)存在的內(nèi)存空間。
? ? ? 那么python中一切皆對(duì)象什么意思呢?還是拿上面的例子來(lái)說(shuō), int a = 1, 在這里,a代表了一個(gè)對(duì)象,一個(gè)真實(shí)的內(nèi)存地址,那么1是什么呢? 1是一個(gè)立即數(shù),是一個(gè)稍縱即逝的電流。但是在python里面對(duì)于a = 1這個(gè)式子,1其實(shí)是一個(gè)對(duì)象,也就是說(shuō),python里面,1表示的是一塊存放值為1的內(nèi)存空間!!!python一切皆為對(duì)象,就是說(shuō)在python中,所有東西都是一個(gè)具體的內(nèi)存空間!!,不管是數(shù)字,還是字符字符串,他們都是一個(gè)實(shí)際存在的內(nèi)存空間。
二:可變類型變量和不可變類型變量
? ? ? ?首先,我們先明確,python的數(shù)據(jù)類型有6中:數(shù)字number/ 字符串string / 元組 Tuple /? 列表 list / 字典 dictionary / 集合 sets;(bool、int,float,complex(復(fù)數(shù))等都屬于number數(shù)字類型)
? ? ? 可變類型變量:字典/列表/集合
? ? ? 不可變類型變量:數(shù)字/字符串/元組
關(guān)于可變類型和不可變類型變量的定義參考自:python中可變類型和不可變類型 - 百度文庫(kù) (baidu.com)
1:可變類型變量,定義如下:?
也就是說(shuō)可變類型變量實(shí)際上是對(duì)象的引用,也就是對(duì)象的別名,其實(shí)指代的還是對(duì)象本身,所以對(duì)象本身當(dāng)然可以對(duì)自己的數(shù)據(jù)進(jìn)行變換啦。(再次強(qiáng)調(diào),關(guān)于引用和指針的關(guān)系參考“(12條消息) 引用是否有地址的討論的_xx_xjm的博客-CSDN博客“)
?2:不可變類型變量,定義如下:
?所以,不可變類型變量實(shí)際上相當(dāng)于對(duì)象的指針,它存儲(chǔ)的只是對(duì)象的地址,比如a = 1,a這個(gè)變量存儲(chǔ)的實(shí)際上是1這個(gè)對(duì)象的地址,當(dāng)然我們也可以把a(bǔ)當(dāng)作是一個(gè)對(duì)象,在c++里面,a這種存放地址的變量叫做指針變量,實(shí)際上也是一個(gè)對(duì)象,因?yàn)樗彩且粋€(gè)實(shí)際存在的內(nèi)存空間。
三:id函數(shù)的作用(個(gè)人理解,歡迎討論,指正)
? ? ? id函數(shù)對(duì)于可變類型變量和不可變類型變量來(lái)說(shuō),其實(shí)作用是不同的,對(duì)于可變類型變量來(lái)說(shuō),比如a = 1,a是對(duì)象1得引用,也就相當(dāng)于a就是1這個(gè)對(duì)象(這句話還不理解,再看看引用得含義),id(a)取得是對(duì)象1的地址; 而對(duì)于不可變類型變量,比如a = [1,2,3],a其實(shí)是一個(gè)指針變量,也就是說(shuō)a本身也是一個(gè)對(duì)象,a有自己的地址,但id(a)取得是[1,2,3]這個(gè)對(duì)象得地址。
四: +=操作得真實(shí)含義
??關(guān)于 += 的代碼層面的區(qū)別在于:參考:(12條消息) python的+=和=的區(qū)別_Liquor6的博客-CSDN博客
?
? ?先說(shuō)結(jié)論:對(duì)于不可變類型對(duì)象:i += 1和 i = i+1是一樣的,都會(huì)改變 i 的地址(真實(shí)的含義是,都會(huì)改變i這個(gè)指針指向的地址),邏輯上理解為,因?yàn)椴豢勺冾愋妥兞渴侵羔?#xff0c;i指向的是一個(gè)具體的數(shù)值對(duì)象,不同的數(shù)值對(duì)象對(duì)應(yīng)的內(nèi)存地址不同,所以當(dāng) i 指向的數(shù)值改變了以后,i指向的地址也就變了;
? ? ?舉例: 比如本來(lái)i = 1,i是一個(gè)指針變量,它指向了1這個(gè)對(duì)象的內(nèi)存地址,現(xiàn)在 i += 1和 i = i + 1,表示的都是說(shuō) i 這個(gè)指針要指向2這個(gè)對(duì)象的地址,所以,i 指向的地址肯定會(huì)從1變成2,這就是為什么不可變對(duì)象 += 和 =+是一樣的操作。
實(shí)驗(yàn)如下
?
?---------------------------------------------------------------------------------------------------------------------
? ?同理,對(duì)于可變類型對(duì)象,比如a = [1,2,3], [1,2,3]是一個(gè)具體的對(duì)象,a是這個(gè)對(duì)象的引用,所以a += 1表示的是[ 1, 2, 3]這個(gè)對(duì)象自己加1,所以a還是這個(gè)對(duì)象的引用,但是a = a + 1則不同了,因?yàn)槭且?#xff0c;所以a = a + 1則表示a現(xiàn)在引用的應(yīng)該是a + 1表示的[2,3,4]這個(gè)對(duì)象的地址,所以a = a + 1導(dǎo)致內(nèi)存地址改變了。
實(shí)驗(yàn)如下:
?
結(jié)果:
?
可以看見(jiàn),雖然a = [1,2,3,4],但是a這個(gè)[1,2,3,4]對(duì)象,實(shí)際上是[1,2,3]這個(gè)對(duì)象變來(lái)的,和本來(lái)的[1,2,3,4]對(duì)象是兩個(gè)東西,也就是說(shuō),這里a和[1,2,3,4]對(duì)象表示的是兩塊內(nèi)存空間,只不過(guò)兩塊內(nèi)存空間保存的值是相同的。
再看a = a + [5]以后,這個(gè)時(shí)候a的地址是改變了的,它變成了[1,2,3,4,5]的地址,這里有一點(diǎn)小意思,因?yàn)槲覀兪窃赼 = a +[5]之前打印的[1,2,3,4,5]的id,所以,這時(shí)候[1,2,3,4,5]應(yīng)該是已經(jīng)被內(nèi)存建立起來(lái)了,因此此時(shí)的a直接指向了[1,2,3,4,5]的內(nèi)存地址,那么為什么此時(shí)[1,2,3,4,5]的地址和[1,2,3,4]的地址相同呢?因?yàn)檫@個(gè)時(shí)候,python其實(shí)是值記住了這個(gè)列表中1這個(gè)元素的地址,id([1,2,3,4])和id([1,2,3,4,5])返回的其實(shí)都是這個(gè)列表首元素1的地址。我們意義做如下實(shí)驗(yàn),表明[1,2,3,4])和id([1,2,3,4,5]其實(shí)是一塊地址空間:
?
?所以,我們來(lái)解釋為什么這個(gè)時(shí)候a的地址就是[1,2,3,4,5]的地址,因?yàn)檫@時(shí)候內(nèi)存中已經(jīng)有一塊連續(xù)的[1,2,3,4,5]了,并且這個(gè)值沒(méi)有給任何變量(也就是沒(méi)有引用),所以直接分配給了a。
那么為什么在a之后的[1,2,3,4,5]的地址又變成了最開(kāi)始a=[1,2,3]的地址了呢?因?yàn)檫@時(shí)候a指向了新的[1,2,3,45]的地址,本來(lái)的[1,2,3]就被釋放了,那么這時(shí)候的[1,2,3]就是沒(méi)人管的了,那么python直接在這個(gè)基礎(chǔ)上分發(fā)[1,2,3,4,5]的地址。由此可以看出python的內(nèi)存管理機(jī)制確實(shí)很出色。更多的實(shí)驗(yàn)可以參照以下代碼自己跑一遍:
?
補(bǔ)充:另外python中numpy數(shù)組是可變類型的, pytorch的張量和numpy數(shù)組共享底層內(nèi)存,所以是可變類型,這就是為什么網(wǎng)絡(luò)運(yùn)行過(guò)程中,不能有原地+=操作。tensorflow的張量是不可變的。pytorch和tensorflow的張量確實(shí)是不同的。
參考:TensorFlow vs PyTorch 2: 張量(Tensor) - 簡(jiǎn)書(shū) (jianshu.com)
五:由可變不可變類型對(duì)象引出的深淺拷貝