从Stackoverflow上的一些答案中,我开始知道从-5到256相同的内存位置被引用,因此我们得到:
>>> a = 256
>>> a is 256
True
Run Code Online (Sandbox Code Playgroud)
现在来了扭曲(在标记重复之前参见此行):
>>> a = 257
>>> a is 257
False
Run Code Online (Sandbox Code Playgroud)
这是完全理解的,但现在如果我这样做:
>>> a = 257; a is 257
True
>>> a = 12345; a is 12345
True
Run Code Online (Sandbox Code Playgroud)
为什么?
你所看到的是CPython中编译器的优化(它将你的源代码编译成解释器运行的字节码).每当在一个步骤中编译的一块代码中的几个不同位置使用相同的不可变常量值时,编译器将尝试对每个位置使用对同一对象的引用.
因此,如果您在交互式会话中在同一行上执行多个赋值,您将获得对同一对象的两个引用,但如果您使用两个单独的行,则不会:
>>> x = 257; y = 257 # multiple statements on the same line are compiled in one step
>>> print(x is y) # prints True
>>> x = 257
>>> y = 257
>>> print(x is y) # prints False this time, since the assignments were compiled separately
Run Code Online (Sandbox Code Playgroud)
这种优化出现的另一个地方是函数体.整个函数体将被编译在一起,因此函数中任何地方使用的任何常量都可以组合,即使它们位于不同的行上:
def foo():
x = 257
y = 257
return x is y # this will always return True
Run Code Online (Sandbox Code Playgroud)
虽然调查像这样的优化很有意思,但你不应该在普通代码中依赖这种行为.不同的Python解释器,甚至不同版本的CPython可能会以不同的方式进行这些优化,或者根本不进行.如果您的代码依赖于特定的优化,那么对于试图在自己的系统上运行它的其他人来说,它可能会完全被破坏.
作为一个例子,我在上面的第一个代码块中显示的同一行上的两个赋值在Spyder(我首选的IDE)内的交互式shell中执行时,不会导致对同一对象的两个引用.我不知道为什么这种特定情况与传统交互式shell中的情况不同,但不同的行为是我的错,因为我的代码依赖于特定于实现的行为.