Python代碼塊緩存、小數據池

引子
前幾天遇到了這樣一道Python題目:a=‘123’,b=‘123’,下列哪一個是正確的?python

A. a != b緩存

B. a is b函數

C. a==123學習

D. a + b =246
正確答案是B
是的,我選錯了,我當時以爲沒有正確答案,緣由是我當時已經知道Python中 == 與 != 是比較兩邊的數值是否相等,很顯然 a==b,我也知道 is 比較的是兩邊的內存地址是否相同,而內存地址是否相同是經過比較 id(a) 是否等於id(b)來知道的,而我想固然地認爲a和b是兩個不同的變量,內存地址確定不相同,因而認爲B選項是錯誤的。然而,我不知道的是,Python中還存在有代碼塊緩存、 小數據池 的概念。對於Python我只是直接上手寫代碼了,以爲很簡單,然而對於其背後的深層知識還有不少欠缺,之後須要多多學習和記錄總結。
代碼塊的緩存機制
代碼塊
Python程序是由代碼塊構造的,一個模塊、一個函數、一個類、一個文件等都是一個代碼塊,特別地,在Python解釋器交互環境中,每一個命令都是一個代碼塊。
緩存機制
Python在執行同一個代碼塊時,遇到初始化變量的命令時,它會將初始化的這個變量與其值存儲在一個字典中,在遇到新的變量時,會先在字典中查詢記錄,若是該變量對應的值的記錄已經存在,則該變量會重複使用這個值,即會把先後兩個變量指向同一個值對象,值對象在內存中只存在一個。這就是代碼塊的緩存機制,緩存機制的適用類型有:int、float、str、bool。命令行

int、float:任何數字在同一代碼塊下都會複用;
bool:True和False在字典中會以1和0的方式存在,所以也都會被複用;
str:緩存機制符合一下規則:對象

非乘法獲得的字符串都會被緩存複用,如;內存

s1='中文xa#!@jndslskkaskakskkkkkkkkdfjkd()&^$$ksjfkls'
s2='中文xa#!@jndslskkaskakskkkkkkkkdfjkd()&
^$$ksjfkls'
print(s1 is s2) # True字符串

乘法獲得的字符串分兩種狀況:
1)乘數爲1時,同非乘法獲得的字符串同樣,都知足代碼塊的緩存機制,如:import

s1='中文xa#!@jndslskkaskakskkkkkkkkdfjkd()&^$$ksjfkls' 1
s2='中文xa#!@jndslskkaskakskkkkkkkkdfjkd()&^$$ksjfkls' 1
print(s1 is s2) # True變量

2)乘數>=2時,僅包含大小寫字母、數字、下劃線而且總長度 <=20 的字符串才知足代碼塊的緩存機制,如:
s1='中文xa#!@jndslskkaskakskkkkkkkkdfjkd()&^$$ksjfkls' 2
s2='中文xa#!@jndslskkaskakskkkkkkkkdfjkd()&^$$ksjfkls' 2
print(s1 is s2) # False 總長度超過20且包含除字母、數字、下劃線的字符

s3='中文xa#!@j' * 2
s4='中文xa#!@j' * 2
print(s3 is s4) # False 包含除字母、數字、下劃線的字符

s5='2a_j' * 6
s6='2a_j' * 6
print(s5 is s6) # False 總長度超過20

s7='2a_j' * 5
s8='2a_j' * 5
print(s7 is s8) # True

小數據池
小數據池即小整數緩存機制,Python自動將 -5~256 之間的整數進行了緩存,也將必定規則的字符串在字符串駐留池中建立了一份,即在內存中只建立一份。它主要是針對不一樣代碼塊之間的緩存機制。
1.int :小數據池的範圍是 -5~256,多個變量都指向在此範圍內的同一個數字時,它們在內存中都指向同一個內存地址,超過此範圍則指向不一樣的內存地址,以命令行爲例(每行命令爲一個代碼塊,不一樣行的命令爲不一樣的代碼塊):

a=256
b=256
a is b
True

a=257
b=257
a is b
False

a=-5
b=-5
a is b
True

a=-6
b=-6
a is b
False

這裏,我還順便試了一下float類型的數據是否符合此原則,實事實證實是不符合的:

a=0.0
b=0.0
a is b
False

a=-0.1
b=-0.1
a is b
False

bool:至關於整數中的1和0,所以知足緩存複用:

a = True
b = True
a is b
True

字符串:依然分爲好幾種狀況:

長度爲0或者1,默認都採用了駐留機制:

s1='a'
s2='a'
s1 is s2
True

s3=''
s4=''
s3 is s4
True

s5='#'
s6='#'
s5 is s6
True

長度>1,僅包含字母、數字、下劃線時,纔會採用駐留機制:

s1='@a'
s2='@a'
s1 is s2
False

s3='s_s111111111111aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
s4='s
_s111111111111aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
s3 is s4
True

用乘法獲得的字符串,乘數爲1時,僅含字母、數字、下劃線時(不限制長度),纔會採用駐留機制,其它字符乘數爲1且長度<=1時,纔會採用駐留機制:

s1='@'1
s2='@'
1
s1 is s2
True

s3='@#a'1
s4='@#a'
1
s3 is s4
False

用乘法獲得的字符串,乘數 >=2 時,僅含字母、數字、下劃線且總長度<=20,纔會採用駐留機制:

s1='ab_@'5
s2='ab_@'
5
s1 is s2
False #包含其它字符

s3='ab_1'6
s4='ab_1'
6
s3 is s4
False #總長度超過20

s5='ab_1'5
s6='ab_1'
5
s5 is s6
True

指定駐留
除了小數據池規則之外,你能夠指定任意的字符串加入到小數據池中,讓其只在內存中建立一個對象,多個變量都是指向這一個字符串,這就是指定駐留,方法以下:

from sys import intern #python2中import貌似會報錯
s1 = intern('ab_@'5)
s2 = intern('ab_@'
5)
s1 is s2
True

總結

若是在同一代碼塊下,則採用同一代碼塊下的換緩存機制;
若是是不一樣代碼塊,則採用小數據池的駐留機制,該機制比代碼塊緩存機制要嚴格一些;
特殊狀況下,採用指定駐留。

寫完本身都有點暈了,的確容易記混出錯,不過不要緊啦,先知道有這麼個規則概念,而後多去手動嘗試使用就好啦,加油,共勉~

相關文章
相關標籤/搜索