虽然这个问题在实践中没有任何实际用途,但我很好奇 Python 是如何进行字符串实习的。我注意到以下内容。
>>> "string" is "string"
True
正如我所料。
你也可以这样做。
>>> "strin"+"g" is "string"
True
这很聪明!
但你不能这样做。
>>> s1 = "strin"
>>> s2 = "string"
>>> s1+"g" is s2
False
为什么 Python 不评估 s1+"g"
,并意识到它与 s2
相同并将其指向相同的地址?最后一个 block 实际上发生了什么让它返回 False
?
最佳答案
这是特定于实现的,但您的解释器可能正在实习编译时常量,而不是运行时表达式的结果。
以下使用 CPython 3.9.0+。
在第二个示例中,表达式 "strin"+"g"
在编译时被计算,并被替换为 "string"
。这使得前两个示例的行为相同。
如果我们检查字节码,我们会发现它们完全相同:
# 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))
第三个示例涉及运行时连接,其结果不会自动被实习:
# 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
这个字节码是通过以下方式获得的(它在上面打印了几行,这些行与上面给出的第一 block 字节码完全相同):
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 "=="?
关于Python字符串实习,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15541404/