この質問は実際には実用的ではありませんが、Pythonが文字列インターンを行う方法について興味があります。次のことに気付きました。
>> "string" is "string"
>> True
これは予想通りです。
これもできます。
>> "strin"+"g" is "string"
>> True
そして、それはかなり賢いです!
しかし、これはできません。
>> s1 = "strin"
>> s2 = "string"
>> s1+"g" is s2
>> False
なぜPython評価s1+"g"
、およびそれがs1
と同じアドレスを指しますか?最後のブロックでFalse
を返すために実際に何が起こっているのですか?
これは実装固有のものですが、インタープリターはおそらくコンパイル時定数をインターンしているのでしょうが、ランタイム式の結果ではありません。
以下では、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
_
ケース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
を変更しています。 x
とy
の両方は同じ値を持ちますが、同一性は持ちません。
両方ともメモリ内の異なるオブジェクトを指します。したがって、異なるid
およびis
演算子がFalse
を返しました