これは実装固有ですが、インタープリターはおそらくコンパイル時の定数をインターンしますが、実行時の式の結果はインターンしません。
以下では、CPython3.9.0+が使用されます。
2番目の例では、式"strin"+"g"
はコンパイル時に評価され、に置き換えられ"string"
ます。これにより、最初の2つの例は同じように動作します。
バイトコードを調べると、まったく同じであることがわかります。
# s1 = "string"
1 0 LOAD_CONST 0 ('string')
2 STORE_NAME 0 (s1)
# s2 = "strin" + "g"
2 4 LOAD_CONST 0 ('string')
6 STORE_NAME 1 (s2)
このバイトコードは、(上記の後にさらに数行を出力する)で取得されました。
import dis
source = 's1 = "string"\ns2 = "strin" + "g"'
code = compile(source, '', 'exec')
print(dis.dis(code))
3番目の例には、実行時の連結が含まれ、その結果は自動的にインターンされません。
# s3a = "strin"
3 8 LOAD_CONST 1 ('strin')
10 STORE_NAME 2 (s3a)
# s3 = s3a + "g"
4 12 LOAD_NAME 2 (s3a)
14 LOAD_CONST 2 ('g')
16 BINARY_ADD
18 STORE_NAME 3 (s3)
20 LOAD_CONST 3 (None)
22 RETURN_VALUE
このバイトコードは、(上記の前にさらに数行を出力し、それらの行は上記のバイトコードの最初のブロックとまったく同じです)で取得されました。
import dis
source = (
's1 = "string"\n'
's2 = "strin" + "g"\n'
's3a = "strin"\n'
's3 = s3a + "g"')
code = compile(source, '', 'exec')
print(dis.dis(code))
3番目の式の結果を手動でsys.intern()
取得すると、以前と同じオブジェクトが得られます。
>>> import sys
>>> s3a = "strin"
>>> s3 = s3a + "g"
>>> s3 is "string"
False
>>> sys.intern(s3) is "string"
True
また、Python 3.9は、上記の最後の2つのステートメントに対して警告を出力します。
SyntaxWarning:リテラルを含む「is」。「==」という意味ですか?