Python 解释程序和脚本之间关于引用的差异

Python 解释程序和脚本之间关于引用的差异,python,Python,我知道这里发生了什么,请参考: >>> x = 5 >>> y = x >>> id(x) 8729216 >>> id(y) 8729216 我还了解到,对于-5到256之间的整数,Python解释器已经提前初始化了一个整数块,因为它们的使用频率很高,所以我预计会出现以下情况: >>> x = 5 >>> y = 5 >>> id(x) 8729216 >>

我知道这里发生了什么,请参考:

>>> x = 5
>>> y = x
>>> id(x)
8729216
>>> id(y)
8729216
我还了解到,对于-5到256之间的整数,Python解释器已经提前初始化了一个整数块,因为它们的使用频率很高,所以我预计会出现以下情况:

>>> x = 5
>>> y = 5
>>> id(x)
8729216
>>> id(y)
8729216
我不确定的是,如果创建了一个大于256的整数,会发生什么情况,所以我在解释器中键入了一些代码:

>>> x = 1234567890
>>> y = 1234567890
>>> id(x)
140542533943248
>>> id(y)
140542533943088
好的,id值是不同的,所以分配了两个不同的整数对象,它们恰好具有相同的值

我原以为就是这样,但后来我在脚本中运行了相同的代码,id值是相同的:

x = 1234567890
y = 1234567890
print(id(x))
print(id(y))
打印到屏幕上的值:

139663862951888
139663862951888

嗯?在这里,它们引用的是同一个整数对象。给出了什么?

我们可以分解字节码来检查这里发生了什么:

def func():
    x = 1234567890
    y = 1234567890
    print(id(x))
    print(id(y))

import dis
dis.dis(func)
输出为:

  3           0 LOAD_CONST               1 (1234567890)
              3 STORE_FAST               0 (x)

  4           6 LOAD_CONST               1 (1234567890)
              9 STORE_FAST               1 (y)

  5          12 LOAD_GLOBAL              0 (id)
             15 LOAD_FAST                0 (x)
             18 CALL_FUNCTION            1
             21 PRINT_ITEM          
             22 PRINT_NEWLINE       

  6          23 LOAD_GLOBAL              0 (id)
             26 LOAD_FAST                1 (y)
             29 CALL_FUNCTION            1
             32 PRINT_ITEM          
             33 PRINT_NEWLINE       
             34 LOAD_CONST               0 (None)
             37 RETURN_VALUE        
现在我们看到所讨论的实体是使用op代码获取的

文档不太容易理解这里发生了什么,但是基本上,窥视孔优化器以前在这个块中看到过这个常量,所以它将返回相同的常量。显然,这只适用于不可变的文本——这是一个特定于CPython的优化

还请注意,常量可以特定于单个代码对象(这是函数属性):


以上结果是使用python2.7.10和python3.6.0a2生成的。如果您使用
pypy
运行它,您将得到两次
True
打印。

以下解释器示例支持@mgilson的见解,即OP中描述的行为是CPython优化代码对象的产物:

元组分配(单个代码对象:引用优化)

复合语句(单个代码对象:引用优化)

多条语句(多个代码对象:无引用优化)


很好的解释。我不知道反汇编程序,所以谢谢你。这在将来可能会有用。太好了!感谢您进一步澄清这一点。
def test1():
    return 1234567890

def test2():
    return 1234567890

a = test1()
b = test2()

print(a is b)  # False

def test3():
    a = 1234567890
    b = 1234567890
    return a, b

t = test3()
print(t[0] is t[1])  # True
>>> x, y  = 1234567890, 1234567890
>>> x is y
True
>>> x = 1234567890; y = 1234567890
>>> x is y
True
>>> x = 1234567890
>>> y = 1234567890
>>> x is y
False