您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關(guān)python中變量的存儲原理是什么,小編覺得挺實用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
變量的存儲
在高級語言中,變量是對內(nèi)存及其地址的抽象。
對于python而言,python的一切變量都是對象,變量的存儲,采用了引用語義的方式,存儲的只是一個變量的值所在的內(nèi)存地址,而不是這個變量的只本身。
引用語義:在python中,變量保存的是對象(值)的引用,我們稱為引用語義。采用這種方式,變量所需的存儲空間大小一致,因為變量只是保存了一個引用。也被稱為對象語義和指針語義。
值語義:有些語言采用的不是這種方式,它們把變量的值直接保存在變量的存儲區(qū)里,這種方式被我們稱為值語義,例如C語言,采用這種存儲方式,每一個變量在內(nèi)存中所占的空間就要根據(jù)變量實際的大小而定,無法固定下來。
由于python中的變量都是采用的引用語義,數(shù)據(jù)結(jié)構(gòu)可以包含基礎(chǔ)數(shù)據(jù)類型,導(dǎo)致了在python中每個變量中都存儲了這個變量的地址,而不是值本身;
對于復(fù)雜的數(shù)據(jù)結(jié)構(gòu)來說,里面的存儲的也只只是每個元素的地址而已,下面給出基礎(chǔ)類型和數(shù)據(jù)結(jié)構(gòu)類型變量重新賦值的存儲變化:
1.數(shù)據(jù)類型重新初始化對python語義引用的影響
變量的每一次初始化,都開辟了一個新的空間,將新內(nèi)容的地址賦值給變量。對于下圖來說,我們重復(fù)的給str1賦值,其實在內(nèi)存中的變化如下右圖:
從上圖我們可以看出,str1在重復(fù)的初始化過程中,是因為str1中存儲的元素地址由'hello world'的地址變成了'new hello world'的。
2.數(shù)據(jù)結(jié)構(gòu)內(nèi)部元素變化重對python語義引用的影響
對于復(fù)雜的數(shù)據(jù)類型來說,改變其內(nèi)部的值對于變量的影響:
當(dāng)對列表中的元素進(jìn)行一些增刪改的操作的時候,是不會影響到lst1列表本身對于整個列表地址的,只會改變其內(nèi)部元素的地址引用??墒钱?dāng)我們對于一個列表重新初始化(賦值)的時候,就給lst1這個變量重新賦予了一個地址,覆蓋了原本列表的地址,這個時候,lst1列表的內(nèi)存id就發(fā)生了改變。上面這個道理用在所有復(fù)雜的數(shù)據(jù)類型中都是一樣的。
變量賦值
1.str的賦值
我們剛剛已經(jīng)知道,str1的再次初始化(賦值)會導(dǎo)致內(nèi)存地址的改變,從上圖的結(jié)果我們可以看出修改了str1之后,被賦值的str2從內(nèi)存地址到值都沒有受到影響。
看內(nèi)存中的變化,起始的賦值操作讓str1和str2變量都存儲了‘hello world'所在的地址,重新對str1初始化,使str1中存儲的地址發(fā)生了改變,指向了新建的值,此時str2變量存儲的內(nèi)存地址并未改變,所以不受影響。
2.復(fù)雜的數(shù)據(jù)結(jié)構(gòu)中的賦值
剛剛我們看了簡單數(shù)據(jù)類型的賦值,現(xiàn)在來看復(fù)雜數(shù)據(jù)結(jié)構(gòu)變化對應(yīng)內(nèi)存的影響。
上圖對列表的增加修改操作,沒有改變列表的內(nèi)存地址,lst1和lst2都發(fā)生了變化。
對照內(nèi)存圖我們不難看出,在列表中添加新值時,列表中又多存儲了一個新元素的地址,而列表本身的地址沒有變化,所以lst1和lst2的id均沒有改變并且都被添加了一個新的元素。
簡單的比喻一下,我們出去吃飯,lst1和lst2就像是同桌吃飯的兩個人,兩個人公用一張桌子,只要桌子不變,桌子上的菜發(fā)生了變化兩個人是共同感受的。
淺拷貝
首先,我們來了解一下淺拷貝。淺拷貝:不管多么復(fù)雜的數(shù)據(jù)結(jié)構(gòu),淺拷貝都只會copy一層。下面就讓我們看一張圖,來了解一下淺淺拷貝的概念。
看上面兩張圖,我們加入左圖表示的是一個列表
sourcelist,sourcelist = ['str1','str2','str3','str4','str5',['str1','str2','str3','str4','str5']];
右圖在原有的基礎(chǔ)上多出了一個淺拷貝的copylist,
copylist = ['str1','str2','str3','str4','str5',['str1','str2','str3','str4','str5']];
sourcelist和copylist表面上看起來一模一樣,但是實際上在內(nèi)存中已經(jīng)生成了一個新列表,copy了sourceLst,獲得了一個新列表,存儲了5個字符串和一個列表所在內(nèi)存的地址。
我們看下面分別對兩個列表進(jìn)行的操作,紅色的框框里面是變量初始化,初始化了上面的兩個列表;我們可以分別對這兩個列表進(jìn)行操作,例如插入一個值,我們會發(fā)現(xiàn)什么呢?如下所示:
從上面的代碼我們可以看出,對于sourceLst和copyLst列表添加一個元素,這兩個列表好像是獨立的一樣都分別發(fā)生了變化,但是當(dāng)我修改lst的時候,這兩個列表都發(fā)生了變化,這是為什么呢?我們就來看一張內(nèi)存中的變化圖:
我們可以知道sourceLst和copyLst列表中都存儲了一坨地址,當(dāng)我們修改了sourceLst1的元素時,相當(dāng)于用'sourceChange'的地址替換了原來'str1'的地址,所以sourceLst的第一個元素發(fā)生了變化。而copyLst還是存儲了str1的地址,所以copyLst不會發(fā)生改變。
當(dāng)sourceLst列表發(fā)生變化,copyLst中存儲的lst內(nèi)存地址沒有改變,所以當(dāng)lst發(fā)生改變的時候,sourceLst和copyLst兩個列表就都發(fā)生了改變。
這種情況發(fā)生在字典套字典、列表套字典、字典套列表,列表套列表,以及各種復(fù)雜數(shù)據(jù)結(jié)構(gòu)的嵌套中,所以當(dāng)我們的數(shù)據(jù)類型很復(fù)雜的時候,用copy去進(jìn)行淺拷貝就要非常小心。。。
深拷貝
深拷貝——即python的copy模塊提供的另一個deepcopy方法。深拷貝會完全復(fù)制原變量相關(guān)的所有數(shù)據(jù),在內(nèi)存中生成一套完全一樣的內(nèi)容,在這個過程中我們對這兩個變量中的一個進(jìn)行任意修改都不會影響其他變量。下面我們就來試驗一下。
看上面的執(zhí)行結(jié)果,這一次我們不管是對直接對列表進(jìn)行操作還是對列表內(nèi)嵌套的其他數(shù)據(jù)結(jié)構(gòu)操作,都不會產(chǎn)生拷貝的列表受影響的情況。我們再來看看這些變量在內(nèi)存中的狀況:
以上就是python中變量的存儲原理是什么,小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降?。希望你能通過這篇文章學(xué)到更多知識。更多詳情敬請關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。