解释器和脚本之间关于引用的差异

时间:2016-09-08 23:29:37

标签: python

我理解这里发生的事情:

>>> 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

咦?这里他们引用相同的整数对象。是什么给了什么?

2 个答案:

答案 0 :(得分:2)

我们可以反汇编字节码来检查这里发生了什么:

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        

现在我们看到有问题的实体是使用LOAD_CONST操作码获取的。

文档并不是非常容易理解这里发生了什么,但基本上,窥孔优化器在此块之前已经看到了这个常量,因此它将返回相同的常量。显然,这仅适用于不可变的文字 - 而且它是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

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

答案 1 :(得分:1)

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

元组分配(单一代码对象:参考优化)

>>> x, y  = 1234567890, 1234567890
>>> x is y
True

复合语句(单一代码对象:参考优化)

>>> x = 1234567890; y = 1234567890
>>> x is y
True

多个语句(多个代码对象:无参考优化)

>>> x = 1234567890
>>> y = 1234567890
>>> x is y
False