本文除"總結(jié)"外,其余均為認(rèn)識(shí)過程;3.7.5;這部分官方文檔不知道在哪里找,目前沒有找到,有誰知道的可以麻煩留言嗎? 謝謝了!
如果在同一代碼塊下,則采用同一代碼塊下的緩存機(jī)制;
如果是不同代碼塊,則采用小數(shù)據(jù)池的駐留機(jī)制;
需要注意的是,交互式輸入時(shí),每個(gè)命令都是一個(gè)代碼塊;
實(shí)現(xiàn) Intern 保留機(jī)制的方式非常簡單,就是通過維護(hù)一個(gè)字符串儲(chǔ)蓄池,這個(gè)池子是一個(gè)字典結(jié)構(gòu),編譯時(shí),如果字符串已經(jīng)存在于池子中就不再去創(chuàng)建新的字符串,直接返回之前創(chuàng)建好的字符串對象,
如果之前還沒有加入到該池子中,則先構(gòu)造一個(gè)字符串對象,并把這個(gè)對象加入到池子中去,方便下一次獲?。?/p>
長度為0與1的字符串一定會(huì)被駐留;
字符串駐留發(fā)生在程序編譯時(shí);
被駐留的字符串必須由 ASCll 字母, 數(shù)字以及下劃線組成;
Python 程序是由代碼塊構(gòu)造的。塊是一個(gè) Python 程序的文本,它是作為一個(gè)單元執(zhí)行的。
代碼塊:一個(gè)模塊, 一個(gè)函數(shù), 一個(gè)類, 一個(gè)文件等都是一個(gè)代碼塊;
交互方式:在 cmd 中進(jìn)入 Python 解釋器里面,輸入的每一條命令都是一個(gè)代碼塊;
Python 在執(zhí)行同一個(gè)代碼塊的初始化對象的命令時(shí),會(huì)檢查其值是否存在,如果存在,會(huì)將其重用;
滿足代碼塊的緩存機(jī)制則它們在內(nèi)存中只存在一個(gè),即:id相同;
代碼塊的緩存機(jī)制的適用范圍: int(float),str,bool;
int(float): 任何數(shù)字在同一代碼塊下都會(huì)復(fù)用;
bool: True 和 False 在字典中會(huì)以 1,0 方式存在,并且復(fù)用;
str:同一代碼塊中,值相同的字符串在內(nèi)存中只存在一個(gè):
s1 = 'janes@!#*ewq' s2 = 'janes@!#*ewq' print(s1 is s2) # True a1 = 'janes45613256132!@#$%#^%@$%' * 1 b1 = 'janes45613256132!@#$%#^%@$%' * 1 print(a1 is b1) # True s1 = 'hah_' * 6 s2 = 'hah_' * 6 print(s1 is s2) # True
Python 自動(dòng)將 -5~256 的整數(shù)進(jìn)行了緩存,當(dāng)你將這些整數(shù)賦值給變量時(shí),并不會(huì)重新創(chuàng)建對象,而是使用已經(jīng)創(chuàng)建好的緩存對象;
Python會(huì)將滿足一定規(guī)則的字符串在字符串駐留池中,創(chuàng)建一份,當(dāng)你將這些字符串賦值給變量時(shí),并不會(huì)重新創(chuàng)建對象, 而是使用在字符串駐留池中創(chuàng)建好的對象;
bool 值就是 True,F(xiàn)alse,無論你創(chuàng)建多少個(gè)變量指向 True,F(xiàn)alse,它在內(nèi)存中都只存在一個(gè);
小數(shù)據(jù)池也是只針對 int(float),str,bool;
小數(shù)據(jù)池是針對不同代碼塊之間的緩存機(jī)制;
# cmd, -5~256 的小整數(shù)雖然不在同一代碼塊中, 但是它們適用小數(shù)據(jù)池機(jī)制 >>>a = 245 >>>b = 245 >>>a is b # True
# 長度為0與1的字符串一定會(huì)被駐留; # 字符串駐留發(fā)生在程序編譯時(shí); # 被駐留的字符串必須由 ASCll字母, 數(shù)字以及下劃線組成; >>>s1 = '@' >>>s2 = '@' >>>s1 is s2 # True >>>s1 = '' >>>s2 = '' >>>s1 is s2 # True >>>s1 = 'a_b_c' >>>s2 = 'a_b_c' >>>s1 is s2 # True >>>s1 = 'a b_c' >>>s2 = 'a b_c' >>>s1 is s2 # False >>>s1 = 'a_b_c' * 1 >>>s2 = 'a_b_c' * 1 >>>s1 is s2 # True >>>s1 = 'abd_d23' * 3 >>>s2 = 'abd_d23' * 3 >>>s1 is s2 # True >>>a, b = "some_thing!", "some_thing!" >>>a is b # False >>>a, b = "some_thing", "some_thing" >>>a is b # True
a1 = 1000 b1 = 1000 a1 is b1 # True class C1(object): a = 100 b = 100 c = 1000 d = 1000 class C2(object): a = 100 b = 1000 print(C1.a is C1.b) # True print(C1.a is C2.a) # True print(C1.c is C1.d) # True print(C1.c is C2.b) # False
優(yōu)點(diǎn):值相同的字符串的(比如標(biāo)識(shí)符),直接從池里拿來用,避免頻繁的創(chuàng)建和銷毀,提升效率,節(jié)約內(nèi)存;
缺點(diǎn):拼接字符串、對字符串修改之類的影響性能;
因?yàn)槭遣豢勺兊?,所以對字符串修改不?inplace 就地操作,要新建對象,這也是為什么拼接多字符串的時(shí)候不建議用 + 而用 join();
join() 是先計(jì)算出所有字符串的長度,然后一一拷貝,只 new 一次對象;
為避免整數(shù)頻繁申請和銷毀內(nèi)存空間,python 使用了小整數(shù)對象池,Python 對小整數(shù)的定義是 [-5, 256] ,這些整數(shù)對象是提前建立好的,不會(huì)被垃圾回收;
一個(gè) Python 程序中,無論這個(gè)整數(shù)處于 LEGB 中哪個(gè)位置,所有位于這個(gè)范圍內(nèi)的整數(shù)使用的都是同一個(gè)對象;
# 3.7.5, ipython7.18.1 a = -5 b = -5 a is b # True a = -6 b = -6 a is b # False a = 256 b = 256 a is b # True a = 257 b = 257 a is b # Flase
cmd 終端中,大整數(shù)每賦值一次,每次的大整數(shù)都會(huì)重新創(chuàng)建,Pycharm 中,每次運(yùn)行時(shí),所有代碼都加載到內(nèi)存中,屬于一個(gè)整體,所以這個(gè)時(shí)候會(huì)有一個(gè)大整數(shù)對象池處于一個(gè)代碼塊的大整數(shù)是同一個(gè)對象;
c 和 d 處于一個(gè)代碼塊,而 C1.b 和 C2.b 分別有自己的代碼塊,所以不相等;
# cmd 終端 a = 1000 b = 1000 a is b # False -------------------- class C1(object): a = 100 b = 100 c = 1000 d = 1000 class C2(object): a = 100 b = 1000 print(C1.a is C1.b) # True print(C1.a is C2.a) # True print(C1.c is C1.d) # True ?? 難道 cmd 中也有大整數(shù)池 ?? 類加載的時(shí)候是在一塊內(nèi)存中,同值同地址 ?? print(C1.c is C2.b) # False # pycharm 等編輯器中 a = 1000 b = 1000 a is b # True -------------------- class C1(object): a = 100 b = 100 c = 1000 d = 1000 class C2(object): a = 100 b = 1000 print(C1.a is C1.b) # True print(C1.a is C2.a) # True print(C1.c is C1.d) # True print(C1.c is C2.b) # False
Python 解釋器為了提高字符串使用的效率和使用性能,編譯時(shí),使用了 intern(字符串駐留)技術(shù)來提高字符串效率,什么是 intern 機(jī)制?即值同樣的字符串對象僅僅會(huì)保存一份,放在一個(gè)字符串儲(chǔ)蓄池中,是共用的,當(dāng)然,肯定不能改變,這也決定了字符串必須是不可變對象(整數(shù)類型也是不可變對象)??,浮點(diǎn)數(shù)就不行 ;
實(shí)現(xiàn) Intern 保留機(jī)制的方式非常簡單,就是通過維護(hù)一個(gè)字符串儲(chǔ)蓄池,這個(gè)池子是一個(gè)字典結(jié)構(gòu),編譯時(shí),如果字符串已經(jīng)存在于池子中就不再去創(chuàng)建新的字符串,直接返回之前創(chuàng)建好的字符串對象,如果之前還沒有加入到該池子中,則先構(gòu)造一個(gè)字符串對象,并把這個(gè)對象加入到池子中去,方便下一次獲取。;
但是,解釋器內(nèi)部對intern 機(jī)制的使用策略是有考究的,有些場景會(huì)自動(dòng)使用 intern ,有些地方需要通過手動(dòng)方式才能啟動(dòng),看下面幾個(gè)常見情景:
# cmd 中浮點(diǎn)數(shù)沒有被緩存 a = 1.0 b = 1.0 a is b # False # cmd 中并非全部的字符串都會(huì)采用intern機(jī)制; 僅 包括下劃線、數(shù)字、字母的字符串才會(huì)被 intern--類標(biāo)識(shí)符 s1="hello" s2="hello" s1 is s2 # True # 如果有空格,默認(rèn)不啟用intern機(jī)制 s1="hell o" s2="hell o" s1 is s2 # False s1 = "hell!*o" s2 = "hell!*o" print(s1 is s2) # False # 如果一個(gè)字符串長度超過20個(gè)字符,不啟動(dòng)intern機(jī)制 -- 看網(wǎng)上很多都是這么寫的, 不超過二十個(gè)就為真,但是我在自己 3.7/8.5 版本上試了一下,發(fā)現(xiàn)好像沒有限制,不知道是 Python 更新了,還是什么問題…… s1 = "a" * 20 s2 = "a" * 20 s1 is s2 # True s1 = "a" * 21 s2 = "a" * 21 s1 is s2 # True s1 = "ab" * 10 s2 = "ab" * 10 s1 is s2 # True s1 = "ab" * 11 s2 = "ab" * 11 s1 is s2 # True # 'kz' + 'c' 編譯時(shí)已經(jīng)變成 'kzc',而 s1 + 'c' 中 s1 是變量, 會(huì)在運(yùn)行時(shí)進(jìn)行拼接,所以沒有被intern? 'kz' + 'c' is 'kzc' # True s1 = 'kz' s2 = 'kzc' s1+'c' is 'kzc' # False # pycharm 等編輯器中,只要是同一個(gè)字符串,都為 True,并不用是下劃線、數(shù)字、字母的字符串 s1 = "hell o" s2 = "hell o" print(s1 is s2) # True s1 = "hell!*o" s2 = "hell!*o" print(s1 is s2) # True s1 = "a" * 20 s2 = "a" * 20 print(s1 is s2) # True s1 = "a" * 21 s2 = "a" * 21 print(s1 is s2) # True s1 = "ab" * 10 s2 = "ab" * 10 print(s1 is s2) # True s1 = "ab" * 11 s2 = "ab" * 11 print(s1 is s2) # True 'kz' + 'c' is 'kzc' # True s1 = 'kz' s2 = 'kzc' s1+'c' is 'kzc' # False # 編輯器中,float 也被緩存了 a = 1.0 b = 1.0 a is b
以上就是詳解Python 小數(shù)據(jù)池和代碼塊緩存機(jī)制的詳細(xì)內(nèi)容,更多關(guān)于Python 小數(shù)據(jù)池和代碼塊緩存機(jī)制的資料請關(guān)注腳本之家其它相關(guān)文章!
標(biāo)簽:江蘇 衡水 湖州 呼和浩特 畢節(jié) 中山 股票 駐馬店
巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《詳解Python小數(shù)據(jù)池和代碼塊緩存機(jī)制》,本文關(guān)鍵詞 詳解,Python,小,數(shù)據(jù),池,和,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。