受this关于缓存小整数和字符串的问题的启发,我发现了以下我不理解的行为。
>>> 1000 is 10**3
False
我以为我理解了这种行为:1000是很大的缓存。 1000和10 ** 3指向2个不同的对象。但我错了:
>>> 1000 is 1000
True
因此,Python可能会将计算与“正常”整数区别对待。但这种假设也不正确:
>>> 1 is 1**2
True
如何解释这种行为?
答案 0 :(得分: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
这里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
有一个窥孔优化在编译时预先计算常量上的表达式,并且此优化已将10 ** 3
替换为1000
,但优化不会重复使用预先存在的常量。因此,LOAD_CONST
操作码正在加载两个不同的整数对象,索引为0和3,这些是两个不同的 int
对象。
然后有small integers are interned的优化措施;在Python程序的生命周期中,只创建了1
对象的一个副本;这适用于-5到256之间的所有整数。
因此,对于1 is 1**2
情况,Python内部使用内部缓存中的单个int()
对象。这是一个CPython实现细节。
这个故事的寓意是,当你真的想按价值进行比较时,你永远不应该使用is
。始终使用==
作为整数。