web-dev-qa-db-ja.com

Python文字列インターン

この質問は実際には実用的ではありませんが、Pythonが文字列インターンを行う方法について興味があります。次のことに気付きました。

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

これは予想通りです。

これもできます。

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

そして、それはかなり賢いです!

しかし、これはできません。

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

なぜPython評価s1+"g"、およびそれがs1と同じアドレスを指しますか?最後のブロックでFalseを返すために実際に何が起こっているのですか?

77
Ze'ev G

これは実装固有のものですが、インタープリターはおそらくコンパイル時定数をインターンしているのでしょうが、ランタイム式の結果ではありません。

以下では、CPython 2.7.3を使用します。

2番目の例では、式_"strin"+"g"_がコンパイル時に評価され、_"string"_に置き換えられます。これにより、最初の2つの例は同じように動作します。

バイトコードを調べると、まったく同じであることがわかります。

_  # 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)
_

3番目の例には、実行時の連結が含まれ、その結果は自動的にインターンされません。

_  # 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        
_

3番目の式の結果を手動でintern()した場合、以前と同じオブジェクトが得られます。

_>>> s3a = "strin"
>>> s3 = s3a + "g"
>>> s3 is "string"
False
>>> intern(s3) is "string"
True
_
80
NPE

ケース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

さて、あなたの質問は、なぜケース1ではIDが同じで、ケース2では同じではないのかということです。
ケース1では、文字列リテラル"123"からxおよびyへ。

文字列は不変であるため、インタプリタが文字列リテラルを一度だけ格納し、すべての変数が同じオブジェクトを指すようにすることは理にかなっています。
したがって、IDが同一であることがわかります。

ケース2では、連結を使用してxを変更しています。 xyの両方は同じ値を持ちますが、同一性は持ちません。
両方ともメモリ内の異なるオブジェクトを指します。したがって、異なるidおよびis演算子がFalseを返しました

0
cppcoder