Python Int Object上的奇怪id结果

时间:2014-08-13 08:49:47

标签: python

我写了三行相同的代码并得到不同的结果,首先我在一个交互式shell中运行它:

>>> a = 10000
>>> b = 10000
>>> a is b
False

>>> a = 10000; b = 10000; a is b
True

然后我有一个包含以下内容的Python文件:

a = 10000
b = 10000
print a is b

我运行它并获得True

我的Python环境:

Python 2.7.5 (default, Mar  9 2014, 22:15:05) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

这里发生了什么?每个人都在谈论编译,有没有人知道交互式shell如何编译和运行这些代码行?

4 个答案:

答案 0 :(得分:3)

如果你把任何一个放入一个函数中,它也会评估True。发生的事情是Python生成一个在将函数编译成字节码时使用的常量列表,并且相等的常量将“折叠”为一个加载两次的值。在编译一行代码*

时,交互式解释器看起来一样

所以这里是使用dis获得的其中一个函数的字节码 - 对于行号之外的任何方法实际上都是相同的,所以我不在这里复制。< / p>

  2           0 LOAD_CONST               1 (10000)
              3 STORE_FAST               0 (a)
              6 LOAD_CONST               1 (10000)
              9 STORE_FAST               1 (b)
             12 LOAD_FAST                0 (a)
             15 LOAD_FAST                1 (b)
             18 COMPARE_OP               8 (is)
             21 RETURN_VALUE

这是为了:

def func():
    a = 10000; b = 10000; return a is b
from dis import dis
dis(func)

请注意,两个LOAD_CONST行都有相同的参数。这是对func.__code__.co_consts中的索引的引用,它是一个元组。该元组的元素1是int对象10000

为了完整起见,如果你a = 10000; b = 10000; a is b,这是原始单行compile()的反汇编:

  1           0 LOAD_CONST               0 (10000)
              3 STORE_NAME               0 (a)
              6 LOAD_CONST               0 (10000)
              9 STORE_NAME               1 (b)
             12 LOAD_NAME                0 (a)
             15 LOAD_NAME                1 (b)
             18 COMPARE_OP               8 (is)
             21 POP_TOP
             22 LOAD_CONST               1 (None)
             25 RETURN_VALUE

除了行号/常数,NAMEFAST以及POP_TOP的结尾之外,它基本相似。然而,如果您在单独的行上分配值,那么它不会使用常量执行此操作,因此每次都会创建一个新的int对象。

*为了增加一点吸引力,如果我将单行版本放入我的IPython笔记本中,a is bFalse

答案 1 :(得分:1)

我认为这是编译时优化。在第一种情况下,您正在编译a = 10000然后编译b = 10000,因此字节码编译器没有(简单)方法来确定它们的身份。

在其他情况下,编译器会看到ab使用相同的文字初始化,之后不会更改。

这与小整数优化无关。那个也适用于表达式,即

>> a = 256; b = 256; a is b
True

>> a = 256; b = 256; a + 1 is b + 1
False

相应的代码是Python的窥孔优化的一部分(参见https://github.com/python/cpython/blob/master/Python/peephole.c)。

答案 2 :(得分:0)

虽然是一个新鲜的蟒蛇,试着解释一下。声明&#34;是&#34;会弄清楚事物的内容是否相同。在你的例子中,如果&#34;是&#34;使用过,python会检查&#34; a&#34;和&#34; b&#34;指着同样的事情。如果你改变你的程序: a = 1时 B = 1 a是b 它将打印True 可能与python关于如何存储值

的方法有关

答案 3 :(得分:0)

我只是想通了,实际上这些具有相同id的10000位于编译的代码对象::

>>> code = compile("a = 10000; b = 10000; a is b", "<string>", "exec")
>>> code.co_consts
(10000, None)

编译器进行一些优化,10000只创建一次,因为10000是不可变的:)