这是实现特定的行为,但您的解释器可能会在编译时对常量进行内部化处理,但不会对运行时表达式的结果进行该处理。
以下内容使用的是CPython 3.9.0+。
在第二个示例中,表达式“string” + “g”在编译时被评估,并被替换为“string”。这使得前两个示例的行为相同。
如果我们检查字节码,我们将看到它们完全相同。
1 0 LOAD_CONST 0 ('string')
2 STORE_NAME 0 (s1)
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 8 LOAD_CONST 1 ('strin')
10 STORE_NAME 2 (s3a)
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 对于上述最后两个语句会打印一个警告:
SyntaxWarning: "is" with a literal. Did you mean "=="?
"string1" + "s2"
,10 + 3*20
, 等等),但将生成的序列限制在20个元素以内(防止[None] * 10**1000
过度扩展字节码)。正是这种优化把"strin" + "g"
转换成了"string"
,结果长度小于20个字符。 - Martijn Pietersintern()
函数特别进行内部化,否则不会进行内部化。 - Martijn Pietersintern
函数的人 - 它已经移动到sys.intern。 - Timofey Chernousov