下面是Python字符串的一些微妙的特性,絕對會讓你大吃一驚。python
案例一:學習
>>> a = "some_string" >>> id(a) 140420665652016 >>> id("some" + "_" + "string") # 注意兩個的id值是相同的. 140420665652016
案例二:優化
>>> a = "wtf" >>> b = "wtf" >>> a is b True >>> a = "wtf!" >>> b = "wtf!" >>> a is b False >>> a, b = "wtf!", "wtf!" >>> a is b True # 3.7 版本返回結果爲 False.
案例三:spa
>>> 'a' * 20 is 'aaaaaaaaaaaaaaaaaaaa' True >>> 'a' * 21 is 'aaaaaaaaaaaaaaaaaaaaa' False # 3.7 版本返回結果爲 True #在學習Python的過程當中,每每由於沒有資料或者沒人指導從而致使本身不想學下去了,所以我特地準備了個羣 592539176 ,羣裏有大量的PDF書籍、教程都給你們無償使用!無論是學習到哪一個階段的小夥伴均可以獲取到本身相對應的資料!
很好理解, 對吧?code
這些行爲是因爲 Cpython 在編譯優化時, 某些狀況下會嘗試使用已經存在的不可變對象而不是每次都建立一個新對象. (這種行爲被稱做字符串的駐留[string interning])對象
發生駐留以後, 許多變量可能指向內存中的相同字符串對象. (從而節省內存)blog
在上面的代碼中, 字符串是隱式駐留的. 什麼時候發生隱式駐留則取決於具體的實現. 這裏有一些方法能夠用來猜想字符串是否會被駐留:教程
全部長度爲 0 和長度爲 1 的字符串都被駐留.ip
字符串在編譯時被實現 ('wtf'
將被駐留, 可是 ''.join(['w', 't', 'f'])
將不會被駐留)內存
字符串中只包含字母,數字或下劃線時將會駐留. 因此 'wtf!'
因爲包含 !
而未被駐留. 能夠在【地址1】找到 CPython 對此規則的實現.
當在同一行將 a
和 b
的值設置爲 "wtf!"
的時候, Python 解釋器會建立一個新對象, 而後同時引用第二個變量(譯: 僅適用於3.7如下, 詳細狀況請看【地址2】). 若是你在不一樣的行上進行賦值操做, 它就不會「知道」已經有一個 wtf!
對象 (由於 "wtf!"
不是按照上面提到的方式被隱式駐留的). 它是一種編譯器優化, 特別適用於交互式環境.
常量摺疊(constant folding) 是 Python 中的一種 窺孔優化(peephole optimization) 技術. 這意味着在編譯時表達式 'a'*20
會被替換爲 'aaaaaaaaaaaaaaaaaaaa'
以減小運行時的時鐘週期. 只有長度小於 20 的字符串纔會發生常量摺疊. (爲啥? 想象一下因爲表達式 'a'*10**10
而生成的 .pyc
文件的大小). 相關的源碼實如今【地址3】.
若是你是使用 3.7 版本中運行上述示例代碼, 會發現部分代碼的運行結果與註釋說明相同. 這是由於在 3.7 版本中, 常量摺疊已經從窺孔優化器遷移至新的 AST 優化器, 後者能夠以更高的一致性來執行優化. (由 Eugene Toder 和 INADA Naoki 在 bpo-29469 和 bpo-11549 中貢獻.)
(譯: 可是在最新的 3.8 版本中, 結果又變回去了. 雖然 3.8 版本和 3.7 版本同樣, 都是使用 AST 優化器. 目前不肯定官方對 3.8 版本的 AST 作了什麼調整.