为什么 Python 处理 '1 is 1**2' 与 '1000 is 10**3' 不同? [英] Why does Python handle '1 is 1**2' differently from '1000 is 10**3'?

查看:50
本文介绍了为什么 Python 处理 '1 is 1**2' 与 '1000 is 10**3' 不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

灵感来自 这个 关于缓存小整数和字符串的问题 我发现了以下我不明白的行为.

<预><代码>>>>1000 是 10**3错误的

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

<预><代码>>>>1000 是 1000真的

所以,也许 Python 对待计算的方式与普通"整数不同.但这种假设也不正确:

<预><代码>>>>1 是 1**2真的

如何解释这种行为?

解决方案

这里有两件独立的事情:Python 将 int 文字(和其他文字)存储为带有编译字节码的常量 小整数对象作为单例缓存.

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

<预><代码>>>>导入文件>>>compile('1000 is 1000', '', 'eval').co_consts(1000,)>>>dis.dis(compile('1000 is 1000', '', 'eval'))1 0 LOAD_CONST 0 (1000)3 LOAD_CONST 0 (1000)6 COMPARE_OP 8 (是)9 RETURN_VALUE

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

将此与 1000 is 10 ** 3 的情况进行比较:

<预><代码>>>>compile('1000 is 10**3', '', 'eval').co_consts(1000, 10, 3, 1000)>>>dis.dis(compile('1000 is 10**3', '', 'eval'))1 0 LOAD_CONST 0 (1000)3 LOAD_CONST 3 (1000)6 COMPARE_OP 8 (是)9 RETURN_VALUE

有一个窥孔优化,在编译时预先计算常量上的表达式,这个优化已经用1000代替了10 ** 3,但优化没有t 重用预先存在的常量.结果,LOAD_CONST 操作码加载了两个不同的整数对象,索引为 0 和 3,它们是两个不同的 int 对象.

然后有一些优化,其中小整数被实习;在 Python 程序的生命周期内,只会创建 1 对象的一个​​副本;这适用于 -5 到 256 之间的所有整数.

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

这个故事的寓意是,当您真的想按值进行比较时,永远不要使用 is.对于整数,始终使用 ==.

Inspired by this question about caching small integers and strings I discovered the following behavior which I don't understand.

>>> 1000 is 10**3
False

I thought I understood this behavior: 1000 is to big to be cached. 1000 and 10**3 point to 2 different objects. But I had it wrong:

>>> 1000 is 1000
True

So, maybe Python treats calculations differently from 'normal' integers. But that assumption is also not correct:

>>> 1 is 1**2
True

How can this behavior be explained?

解决方案

There are two separate things going on here: Python stores int literals (and other literals) as constants with compiled bytecode and small integer objects are cached as singletons.

When you run 1000 is 1000 only one such constant is stored and reused. You are really looking at the same object:

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

Here LOAD_CONST refers to the constant at index 0; you can see the stored constants in the .co_consts attribute of the bytecode object.

Compare this to the 1000 is 10 ** 3 case:

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

There is a peephole optimization that pre-computes expressions on constants at compile time, and this optimization has replaced 10 ** 3 with 1000, but the optimization doesn't re-use pre-existing constants. As a result, the LOAD_CONST opcodes are loading two different integer objects, at index 0 and 3, and these are two different int objects.

Then there are optimisations in place where small integers are interned; only one copy of the 1 object is ever created during the lifetime of a Python program; this applies to all integers between -5 and 256.

Thus, for the 1 is 1**2 case, the Python internals use a singleton int() object from the internal cache. This is a CPython implementation detail.

The moral of this story is that you should never use is when you really wanted to compare by value. Use == for integers, always.

这篇关于为什么 Python 处理 '1 is 1**2' 与 '1000 is 10**3' 不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆