为什么Python处理'1是1**2'与'1000是10**3'不同?

Ora*_*Tux 26 python reference python-internals semantics

这个关于缓存小整数和字符串的问题的启发,我发现了以下我不理解的行为.

>>> 1000 is 10**3
False
Run Code Online (Sandbox Code Playgroud)

我以为我理解了这种行为:1000是很大的缓存.1000和10**3指向2个不同的对象.但我错了:

>>> 1000 is 1000
True
Run Code Online (Sandbox Code Playgroud)

因此,Python可能会将计算与"正常"整数区别对待.但这种假设也是不正确的:

>>> 1 is 1**2
True
Run Code Online (Sandbox Code Playgroud)

如何解释这种行为?

Mar*_*ers 42

有两个独立的事情怎么回事:Python的商店int文字(和其他文字)作为编译的字节常数小整数对象缓存为单身.

当你1000 is 1000只运行一个这样的常量时,就会存储并重用它.你真的在看同一个对象:

>>> import dis
>>> compile('1000 is 1000', '<stdin>', 'eval').co_consts
(1000,)
>>> dis.dis(compile('1000 is 1000', '<stdin>', 'eval'))
  1           0 LOAD_CONST               0 (1000) 
              3 LOAD_CONST               0 (1000) 
              6 COMPARE_OP               8 (is) 
              9 RETURN_VALUE         
Run Code Online (Sandbox Code Playgroud)

这里LOAD_CONST指的是索引0处的常量; 您可以.co_consts在字节码对象的属性中看到存储的常量.

将此与1000 is 10 ** 3案例进行比较:

>>> compile('1000 is 10**3', '<stdin>', 'eval').co_consts
(1000, 10, 3, 1000)
>>> dis.dis(compile('1000 is 10**3', '<stdin>', 'eval'))
  1           0 LOAD_CONST               0 (1000) 
              3 LOAD_CONST               3 (1000) 
              6 COMPARE_OP               8 (is) 
              9 RETURN_VALUE         
Run Code Online (Sandbox Code Playgroud)

有在编译时是预先计算的常量表达式窥视孔优化,这种优化已经取代了10 ** 31000,但优化不重新使用预先存在的常数.结果,LOAD_CONST操作码在索引0和3处加载两个不同的整数对象,这些是两个不同的 int对象.

然后就是在小整数被实习的地方进行优化; 1在Python程序的生命周期中,只创建了一个对象副本; 这适用于-5到256之间的所有整数.

因此,对于这种1 is 1**2情况,Python内部使用int()内部缓存中的单个对象.这是一个CPython实现细节.

这个故事的寓意是,is当你真正想要按价值进行比较时,你永远不应该使用它.==始终使用整数.