sys.intern() 无法在切片时实习字符串

问题描述

为什么 sys.intern() 无法实习这个字符串?

>>> from sys import intern
>>> "abcd"[:-1] == "abc"
True
>>> "abcd"[:-1] is "abc"
False
>>> intern("abc")
'abc'
>>> "abcd"[:-1] is "abc"
False  # Expected True

(在 cpython 3.7.4 上)

解决方法

字符串文字已经被实习,它是你需要手动实习的计算表达式。

from sys import intern
print("abcd"[:-1] is "abc")  # False
print(intern("abcd"[:-1]) is "abc")  # True
print("abcd"[:-1] is "abc")  # False

intern 并不意味着“每当这个字符串在程序中的任何地方产生时,都将其更改为内部引用”,它只是返回给定字符串的内部引用。

s1 = "abc"
s2 = "abc"
s3 = "abcd"[:-1]
s4 = intern(s3)
for s in [s1,s2,s3,s4]:
  print(id(s))
140002991598512
140002991598512
140002990838576
140002991598512
,

你的期望是错误的。在创建代码对象 (here) 而不是在创建任何字符串对象时,名称、字符串常量和类似内容会被保留。

"abcd"[:-1] 的字符串是在运行时创建的,因此不会被留存。从理论上讲,如果优化器会在编译时评估这个表达式,它可以被实习,就像它发生在

>>> "a"*5 is "aaaaa"  #True

但它只是一个实现细节,例如

>>> "a"*4097

将不再在编译时进行评估,因此不会被实习。