2013-03-21 27 views
54

儘管這個問題在實踐中沒有任何實際用處,但我對Python如何進行字符串實習感到好奇。我注意到了以下幾點。Python string interning

>> "string" is "string" 
>> True 

這是我所期望的。

您也可以這樣做。

>> "strin"+"g" is "string" 
>> True 

而且這很聰明!

但你不能這樣做。

>> s1 = "strin" 
>> s2 = "string" 
>> s1+"g" is s2 
>> False 

爲什麼不Python的評估s1+"g",意識到這一點是一樣的s1並將其指向相同的地址?實際上在最後一個街區發生的事情是什麼讓它返回False

回答

60

這是特定於實現的,但您的解釋器可能是實習編譯時常量,但不是運行時表達式的結果。

以下我使用CPython 2.7.3。

在第二個示例中,在編譯時評估表達式"strin"+"g",並將其替換爲"string"。這使得前兩個例子的行爲相同。

如果我們檢查字節碼,我們可以看到,他們是完全一樣的:

# s1 = "string" 
    2   0 LOAD_CONST    1 ('string') 
       3 STORE_FAST    0 (s1) 

    # s2 = "strin" + "g" 
    3   6 LOAD_CONST    4 ('string') 
       9 STORE_FAST    1 (s2) 

第三個例子涉及運行時間串聯,其結果不會自動扣留:

# s3a = "strin" 
    # s3 = s3a + "g" 
    4   12 LOAD_CONST    2 ('strin') 
      15 STORE_FAST    2 (s3a) 

    5   18 LOAD_FAST    2 (s3a) 
      21 LOAD_CONST    3 ('g') 
      24 BINARY_ADD   
      25 STORE_FAST    3 (s3) 
      28 LOAD_CONST    0 (None) 
      31 RETURN_VALUE   

如果你手動intern()第三個表達式的結果,你會得到相同的對象之前:

>>> s3a = "strin" 
>>> s3 = s3a + "g" 
>>> s3 is "string" 
False 
>>> intern(s3) is "string" 
True 
+13

你是怎麼得到這個性感的輸出? – Serdalis 2013-03-21 07:19:33

+13

@Serdalis:http://docs.python.org/2/library/dis.html – NPE 2013-03-21 07:22:59

+12

並記錄在案:在常量Python的窺視孔優化將預先計算的算術運算('「字符串1」 +「S2」' ,'10 + 3 * 20'等),但是會將結果*序列限制在20個元素中(以防止[[None] * 10 ** 1000'過度擴展字節碼)。正是這種優化將''strin'「+」g「'摺疊成''string'';結果短於20個字符。 – 2013-07-10 09:12:36

0

案例1

>>> x = "123" 
>>> y = "123" 
>>> x == y 
True 
>>> x is y 
True 
>>> id(x) 
50986112 
>>> id(y) 
50986112 

案例2

>>> x = "12" 
>>> y = "123" 
>>> x = x + "3" 
>>> x is y 
False 
>>> x == y 
True 

現在,你的問題是,爲什麼id爲1的情況下相同的,而不是在案件2
在案例1,您已將字符串文字"123"分配給xy

由於字符串是不可變的,所以解釋器只存儲一次字符串字面值並將所有變量指向同一個對象是有意義的。
因此,您將ID看作相同。

在情況2中,您正在使用串聯來修改xxy都具有相同的值,但標識不相同。
兩者都指向內存中的不同對象。因此,他們有不同的idis符返回False

+0

爲什麼由於字符串是不可變的,分配x +「3」(並尋找一個新的位置來存儲字符串)不會分配給與y相同的引用? – Andrea 2016-08-09 21:14:40

+0

因爲它需要將新字符串與所有現有字符串進行比較;可能是非常昂貴的操作。它可以在賦值後在後臺執行此操作,以減少內存,但最終會導致更奇怪的行爲:例如'id(x)!= id(x)',因爲字符串在進程中被移動的評估。 – DylanYoung 2017-09-23 19:55:49

+0

@AndreaConte因爲字符串的連接不會在每次生成新字符串時查找所有使用的字符串池的額外工作。在另一方面,翻譯「優化」的表述'X =「12」 +「3」'到'X =「123」'(在單個表達的兩種字符串文字的級聯),以使分配實際執行查找並發現與「y =」123「'相同的」內部「字符串。 – derenio 2017-09-25 08:38:11