1. ホーム
  2. python

[解決済み] Python文字列インターン

2022-10-15 22:14:06

質問

この質問は実際には何の役にも立ちませんが、Pythonがどのように文字列のインターリングを行うのかに興味があります。私は以下のことに気づきました。

>>> "string" is "string"
True

これは予想通りです。

こんなこともできるんですね。

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

と、なかなか気が利いてますね〜。

でも、こんなことはできません。

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

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

どのように解決するのですか?

これは実装に依存しますが、インタープリタはおそらくコンパイル時の定数をインターセプトしていますが、実行時の式の結果はインターセプトしていません。

以下では、CPython 3.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))

もしあなたが手動で 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" がリテラルで表示されました。これは "==" のことでしょうか?