目錄
- 前言
- 總結(jié):
- 1.代碼塊的緩存機(jī)制
- 2.小數(shù)據(jù)池
- 3.優(yōu)缺點(diǎn)
- 小整數(shù)對(duì)象池
- 大整數(shù)對(duì)象池
- 字符串駐留機(jī)制
- 簡單原理:
前言
本文除"總結(jié)"外,其余均為認(rèn)識(shí)過程;3.7.5;這部分官方文檔不知道在哪里找,目前沒有找到,有誰知道的可以麻煩留言嗎? 謝謝了!
總結(jié):
如果在同一代碼塊下,則采用同一代碼塊下的緩存機(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)建好的字符串對(duì)象,
如果之前還沒有加入到該池子中,則先構(gòu)造一個(gè)字符串對(duì)象,并把這個(gè)對(duì)象加入到池子中去,方便下一次獲??;
長度為0與1的字符串一定會(huì)被駐留;
字符串駐留發(fā)生在程序編譯時(shí);
被駐留的字符串必須由 ASCll 字母, 數(shù)字以及下劃線組成;
1.代碼塊的緩存機(jī)制
Python 程序是由代碼塊構(gòu)造的。塊是一個(gè) Python 程序的文本,它是作為一個(gè)單元執(zhí)行的。
代碼塊:一個(gè)模塊, 一個(gè)函數(shù), 一個(gè)類, 一個(gè)文件等都是一個(gè)代碼塊;
交互方式:在 cmd 中進(jìn)入 Python 解釋器里面,輸入的每一條命令都是一個(gè)代碼塊;
Python 在執(zhí)行同一個(gè)代碼塊的初始化對(duì)象的命令時(shí),會(huì)檢查其值是否存在,如果存在,會(huì)將其重用;
滿足代碼塊的緩存機(jī)制則它們?cè)趦?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
2.小數(shù)據(jù)池
Python 自動(dòng)將 -5~256 的整數(shù)進(jìn)行了緩存,當(dāng)你將這些整數(shù)賦值給變量時(shí),并不會(huì)重新創(chuàng)建對(duì)象,而是使用已經(jīng)創(chuàng)建好的緩存對(duì)象;
Python會(huì)將滿足一定規(guī)則的字符串在字符串駐留池中,創(chuàng)建一份,當(dāng)你將這些字符串賦值給變量時(shí),并不會(huì)重新創(chuàng)建對(duì)象, 而是使用在字符串駐留池中創(chuàng)建好的對(duì)象;
bool 值就是 True,F(xiàn)alse,無論你創(chuàng)建多少個(gè)變量指向 True,F(xiàn)alse,它在內(nèi)存中都只存在一個(gè);
小數(shù)據(jù)池也是只針對(duì) int(float),str,bool;
小數(shù)據(jù)池是針對(duì)不同代碼塊之間的緩存機(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
3.優(yōu)缺點(diǎn)
優(yōu)點(diǎn):值相同的字符串的(比如標(biāo)識(shí)符),直接從池里拿來用,避免頻繁的創(chuàng)建和銷毀,提升效率,節(jié)約內(nèi)存;
缺點(diǎn):拼接字符串、對(duì)字符串修改之類的影響性能;
因?yàn)槭遣豢勺兊模詫?duì)字符串修改不是 inplace 就地操作,要新建對(duì)象,這也是為什么拼接多字符串的時(shí)候不建議用 + 而用 join();
join() 是先計(jì)算出所有字符串的長度,然后一一拷貝,只 new 一次對(duì)象;
小整數(shù)對(duì)象池
為避免整數(shù)頻繁申請(qǐng)和銷毀內(nèi)存空間,python 使用了小整數(shù)對(duì)象池,Python 對(duì)小整數(shù)的定義是 [-5, 256] ,這些整數(shù)對(duì)象是提前建立好的,不會(huì)被垃圾回收;
一個(gè) Python 程序中,無論這個(gè)整數(shù)處于 LEGB 中哪個(gè)位置,所有位于這個(gè)范圍內(nèi)的整數(shù)使用的都是同一個(gè)對(duì)象;
# 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
大整數(shù)對(duì)象池
cmd 終端中,大整數(shù)每賦值一次,每次的大整數(shù)都會(huì)重新創(chuàng)建,Pycharm 中,每次運(yùn)行時(shí),所有代碼都加載到內(nèi)存中,屬于一個(gè)整體,所以這個(gè)時(shí)候會(huì)有一個(gè)大整數(shù)對(duì)象池處于一個(gè)代碼塊的大整數(shù)是同一個(gè)對(duì)象;
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
字符串駐留機(jī)制
Python 解釋器為了提高字符串使用的效率和使用性能,編譯時(shí),使用了 intern(字符串駐留)技術(shù)來提高字符串效率,什么是 intern 機(jī)制?即值同樣的字符串對(duì)象僅僅會(huì)保存一份,放在一個(gè)字符串儲(chǔ)蓄池中,是共用的,當(dāng)然,肯定不能改變,這也決定了字符串必須是不可變對(duì)象(整數(shù)類型也是不可變對(duì)象)??,浮點(diǎn)數(shù)就不行 ;
簡單原理:
實(shí)現(xiàn) Intern 保留機(jī)制的方式非常簡單,就是通過維護(hù)一個(gè)字符串儲(chǔ)蓄池,這個(gè)池子是一個(gè)字典結(jié)構(gòu),編譯時(shí),如果字符串已經(jīng)存在于池子中就不再去創(chuàng)建新的字符串,直接返回之前創(chuàng)建好的字符串對(duì)象,如果之前還沒有加入到該池子中,則先構(gòu)造一個(gè)字符串對(duì)象,并把這個(gè)對(duì)象加入到池子中去,方便下一次獲取。;
但是,解釋器內(nèi)部對(duì)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ī)制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
您可能感興趣的文章:- python爬蟲構(gòu)建代理ip池抓取數(shù)據(jù)庫的示例代碼
- python多線程+代理池爬取天天基金網(wǎng)、股票數(shù)據(jù)過程解析
- Python MySQL數(shù)據(jù)庫連接池組件pymysqlpool詳解
- Python實(shí)現(xiàn)Mysql數(shù)據(jù)庫連接池實(shí)例詳解
- Python代碼塊及緩存機(jī)制原理詳解