Python字符串实习

Ze'*_*v G 80 python string internals

虽然这个问题在实践中没有任何实际用途,但我很好奇Python如何进行字符串实习.我注意到以下内容.

>> "string" is "string"
>> True
Run Code Online (Sandbox Code Playgroud)

这是我所期待的.

你也可以这样做.

>> "strin"+"g" is "string"
>> True
Run Code Online (Sandbox Code Playgroud)

这非常聪明!

但你不能这样做.

>> s1 = "strin"
>> s2 = "string"
>> s1+"g" is s2
>> False
Run Code Online (Sandbox Code Playgroud)

为什么Python不会评估s1+"g",意识到它是相同的s1并指向同一个地址?在最后一个块中实际发生了什么让它返回False

NPE*_*NPE 82

这是特定于实现的,但您的解释器可能是实时编译时常量,但不是运行时表达式的结果.

接下来我使用CPython 2.7.3.

在第二个示例中,表达式"strin"+"g"在编译时计算,并替换为"string".这使得前两个示例的行为相同.

如果我们检查字节码,我们会看到它们完全相同:

  # 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)
Run Code Online (Sandbox Code Playgroud)

第三个示例涉及运行时连接,其结果不会自动实现:

  # 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        
Run Code Online (Sandbox Code Playgroud)

如果您要手动intern()执行第三个表达式的结果,您将获得与以前相同的对象:

>>> s3a = "strin"
>>> s3 = s3a + "g"
>>> s3 is "string"
False
>>> intern(s3) is "string"
True
Run Code Online (Sandbox Code Playgroud)

  • 并且为了记录:Python的窥视孔优化将在编译时预先计算常量("string1"+"s2","10 + 3*20"等)的算术运算,但限制了*序列*只有20个元素(防止`[无]*10**1000`过度扩展你的字节码).正是这种优化将"strin"+"g"`折叠成"字符串"`; 结果短于20个字符. (18认同)
  • 并且说得更清楚:这里根本就没有实习.相反,不可变文字作为常量存储在字节码中.对于代码中使用的名称,实例*会发生,但不会对程序创建的字符串值进行,除非由`intern()`函数特别实现. (13认同)
  • 对于那些试图在Python 3中找到`intern`函数的人 - 它被移动到[sys.intern](https://docs.python.org/3/library/sys.html?highlight=sys#sys.intern ) (7认同)

cpp*_*der 5

情况1

>>> x = "123"  
>>> y = "123"  
>>> x == y  
True  
>>> x is y  
True  
>>> id(x)  
50986112  
>>> id(y)  
50986112  
Run Code Online (Sandbox Code Playgroud)

案例2

>>> x = "12"
>>> y = "123"
>>> x = x + "3"
>>> x is y
False
>>> x == y
True
Run Code Online (Sandbox Code Playgroud)

现在,您的问题是为什么 id 在情况 1 中相同,而在情况 2 中不同。在情况 1 中,您已为和
分配了一个字符串文字。"123"xy

由于字符串是不可变的,因此解释器只存储一次字符串并将所有变量指向同一个对象是有意义的。
因此你会看到 id 是相同的。

在情况 2 中,您正在x使用串联进行修改。x和两者y具有相同的值,但身份不同。
两者都指向内存中的不同对象。因此它们有不同的操作idis返回False