本文整理了許多字符串駐留的坑,部分整合自wtfpython英文版,并增加了大量的后續(xù)說明。
# example1:
>>> a ="wtf"
>>> b ="wtf"
>>> a is b
True
# example2:
>>> a ="wtf!"
>>> b ="wtf!"
>>> a is b
False
# example3:
>>> a, b ="wtf!","wtf!"
>>> a is b
True# 3.7 版本返回結(jié)果為 False.
# example4:
>>>'a'*20is'aaaaaaaaaaaaaaaaaaaa'
True
>>>'a'*21is'aaaaaaaaaaaaaaaaaaaaa'
False# 3.7 版本返回結(jié)果為 True
字符串的這些問題,像是在和你說 1 != 1 一樣坑爹。
究其原因,其實(shí)是CPython在編譯的時(shí)候會(huì)自動(dòng)進(jìn)行優(yōu)化,在某些情況下它會(huì)嘗試使用已經(jīng)存在的不可變對(duì)象,而不是創(chuàng)建一個(gè)新的對(duì)象,而恰好,字符串就是不可變對(duì)象。這種使用已存在的不可變對(duì)象的行為被稱為“駐留 ” 。
駐留的原本設(shè)計(jì)意圖是用于節(jié)省內(nèi)存的,但是確實(shí)有時(shí)候會(huì)坑到程序員。怎樣判斷自己的字符串會(huì)否被駐留呢?請(qǐng)看這份代碼:
https://github.com/python/cpython/blob/3.6/Objects/codeobject.c#L19
簡單地來講:
1.所有長度為0和1的字符串都會(huì)被駐留
2.字符串在編譯時(shí)被實(shí)現(xiàn)的會(huì)被駐留(如'wtf'會(huì)被駐留,但是 ''.join(['w', 't', 'f']) 不會(huì))
3.字符串中只包含ASCII下的字母、數(shù)字和下劃線時(shí)會(huì)被駐留. 所以'wtf!'由于包含!不會(huì)被駐留。
我們的example1中,由于發(fā)生了駐留,所以a和b是同一個(gè)字符串對(duì)象。而example2中,由于沒有發(fā)生字符串駐留,a="wtf!"和b="wtf!"實(shí)際上使用的不是同一個(gè)字符串對(duì)象,你可以使用id獲得對(duì)象的唯一標(biāo)志,你會(huì)發(fā)現(xiàn)它們的不同:
a和b都為wtf!時(shí):
>>> a ="wtf!"
>>> b ="wtf!"
>>> a is b
False
>>> a == b
True
>>> id(a)
2272774097864
>>> id(b)
2272774097024
再來看看沒有發(fā)生駐留時(shí)的情況,a和b都為wtf時(shí):
# a和b都為wtf
>>> a ="wtf"
>>> b ="wtf"
>>> a is b
True
>>> a == b
True
>>> id(a)
2272774096744
>>> id(b)
2272774096744
明白了吧?如果你想從結(jié)果識(shí)別對(duì)象是否發(fā)生駐留,關(guān)鍵就看對(duì)象的唯一標(biāo)志有沒有被改變。
不過,如example3所示,當(dāng)你在同一行中將a和b都設(shè)置為 wtf! 的時(shí)候,Python解釋器會(huì)創(chuàng)建一個(gè)新的對(duì)象,然后同時(shí)引用第二個(gè)變量,這時(shí)候它兩的唯一標(biāo)志id就是一樣的。(example3僅適用于python3.7以下,后面被改了)。
example4中,發(fā)生了常量折疊,這其實(shí)也是一種優(yōu)化技術(shù)。編譯時(shí)表達(dá)式 'a'*20 會(huì)被替換成 'aaaaaaaaaaaaaaaaaaaa' (不要數(shù)了,20個(gè)),不過只有長度小于20的字符串才會(huì)發(fā)生常量替換,這就是為什么 'a'*21并不等于 'aaaaaaaaaaaaaaaaaaaaa' (不要數(shù)了,21個(gè)) 。
好,感謝大家的閱讀,今天的.....等等,你以為這就結(jié)束了嗎?還有呢:
>>> a =10
>>> b =10
>>> a is b
True
>>> a =256
>>> b =256
>>> a is b
True
>>> a =257
>>> b =257
>>> a is b
False
這又是為啥啊?
請(qǐng)注意,Python中,對(duì)于整數(shù)對(duì)象,如果其值處于[-5,256]的閉區(qū)間內(nèi),則值相同的對(duì)象是同一個(gè)對(duì)象,否則為不同對(duì)象。我知道你想問,別問,問就是源碼本身就這么寫的。
(其實(shí)主要還是從性能方面考慮,-5到256這段數(shù)值被經(jīng)常使用,因此干脆設(shè)為同一個(gè)對(duì)象重復(fù)使用,避免分配空間—賦予類別—賦予初始值等一系列操作)。
-
字符串
+關(guān)注
關(guān)注
1文章
578瀏覽量
20508 -
編譯
+關(guān)注
關(guān)注
0文章
657瀏覽量
32852 -
python
+關(guān)注
關(guān)注
56文章
4792瀏覽量
84631 -
Examples
+關(guān)注
關(guān)注
0文章
2瀏覽量
1614
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論