111

この質問は実際には実際には使用されませんが、Pythonが文字列インターンをどのように行うかについて興味があります。私は次のことに気づきました。

>>> "string" is "string"
True

これは私が期待した通りです。

これを行うこともできます。

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

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

しかし、これを行うことはできません。

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

なぜPythonは評価せずs1+"g"、それが同じであることに気づきs2、同じアドレスを指すのでしょうか?その最後のブロックで実際に何が起こっているのFalseでしょうか?

4

2 に答える 2

110

これは実装固有ですが、インタープリターはおそらくコンパイル時の定数をインターンしますが、実行時の式の結果はインターンしません。

以下では、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」。「==」という意味ですか?

于 2013-03-21T07:15:55.527 に答える
3

ケース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がケース2ではなくケース1で同じである理由です。ケース1では、文字列リテラルをと
に割り当てました。"123"xy

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

ケース2では、x連結を使用して変更しています。xとの両方のy値は同じですが、同一性は同じではありません。
どちらもメモリ内の異なるオブジェクトを指しています。したがって、それらは異なりidis演算子が返されますFalse

于 2014-09-10T05:56:00.677 に答える