我写了三行相同的代码并得到不同的结果,首先我在一个交互式 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是如何编译和运行这几行代码的?

最佳答案

如果您将其中任何一个放入函数,它也会评估 True 。发生的事情是 Python 制作了一个在将函数编译为字节码时使用的常量列表,并且相等的常量将被“折叠”为一个值,该值被加载两次。看起来交互式解释器在编译一行代码时也做同样的事情*

所以这里是使用 dis 获得的这些函数之一的字节码——除了行号之外,这两种方法实际上都是相同的,所以我不会在这里复制两者。

  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 b 就是 False

关于python - CPython IntObject 上奇怪的 id 结果,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25281892/

10-12 16:55