【问题标题】:Why id function behaves differently with integer and float?为什么 id 函数的行为与整数和浮点数不同?
【发布时间】:2013-04-14 08:05:08
【问题描述】:

我尝试了以下代码,它给了我不同的输出。

>>> foo1 = 4
>>> foo2 = 2+2
>>> id(foo1)
37740064L
>>> id(foo2)
37740064L

>>> foo1 = 4.3
>>> foo2 = 1.3+3.0
>>> id(foo1)
37801304L
>>> id(foo2)
37801232L
>>>

我正在使用 python 2.7.2。为什么 id 函数在 float 的情况下返回不同的值,但在整数的情况下返回相同的值?

【问题讨论】:

    标签: python python-2.7


    【解决方案1】:

    这是因为id 在数值常量中的结果是实现定义的。

    在您的情况下,Python 2.7.2,IIRC,问题在于编译器构建了一些有用的整数常量作为单例(从 -1 到 100 左右)。理由是这些数字被频繁使用,以至于每次需要它们时动态分配它们是没有意义的,它们只是被重复使用。

    但是对于float 的值,常量单例优化没有用处,除了可能是 0.0,它们太多了!因此,每次需要一个新的float 值时,都会分配它,并获得不同的 id。

    要更深入地了解,请阅读源代码! This file 来自 Python3,但思路是一样的:查找 small_ints 数组。

    【讨论】:

    • 0.0 没有被缓存,虽然你没有暗示我只是想我会这么说
    • @jamylak:不,我刚刚看过代码,但我仍然认为这可能是个好主意......
    • 刚刚尝试过,因此接受了您的解决方案>>> aList = ['ammonia', 83, 85, 'lady'] >>> aList ['ammonia', 83, 85, 'lady'] >>> >>> aList[2] 85 >>> >>> id(aList) 135443480 >>> >>> aList[2] = aList[2] + 1 >>> aList[3] = 'stereo' >>> aList ['ammonia', 83, 86, 'stereo'] >>> >>> id(aList) 135443480 >>> >>> aList.append('gaudy') >>> aList.append(aList[2] + 1) >>> aList ['ammonia', 83, 86, 'stereo', 'gaudy', 87] >>> >>> id(aList) 135443480
    【解决方案2】:

    id 从来都不是真正可预测的,即使是整数也不行。使用非常小的整数 24,您恰好碰到了小整数缓存。试试这个:

    >>> a = 12345
    >>> b = 12345
    >>> id(a)
    33525888
    >>> id(b)
    33525852
    >>>
    

    【讨论】:

      【解决方案3】:

      对于预计会经常使用的小整数和字符串,Python 使用内部内存优化。由于 Python 中的任何变量都是对内存对象的引用,因此 Python 只会将如此小的值放入内存中一次。然后,每当将相同的值分配给任何其他变量时,它都会使该变量指向已保存在内存中的对象。这适用于字符串和整数,因为它们是不可变的,如果变量值发生变化,实际上是该变量使用的引用发生了变化,内存中具有原始值的对象本身不会受到影响。

      这就是为什么变量 foo1 和 foo2 在第一种情况下保持对内存中值 4 的相同整数对象的引用,因此 id 是相同的。

      首先,浮点数并不“小”,其次,内存中的相同 4.3 取决于计算可能会保留为 4.3123456789 和 4.31239874654(仅用于解释的示例数字)。所以这两个值是两个不同的对象,但是在计算和显示有意义的部分时看起来是一样的,即 4.3(事实上,对于相同的有意义的浮点数,内存中显然有更多可能的值)。所以在内存中重用同一个浮点数对象是有问题的,毕竟不值得。

      这就是为什么在第二种情况下 foo1 和 foo2 在内存中引用不同的浮点对象,因此具有不同的 id。

      查看有关浮点数如何保存在内存中的更多详细信息:

      http://floating-point-gui.de/

      http://docs.python.org/2/tutorial/floatingpoint.html

      此外,Oracle 文档中有一篇关于浮点数的大文章。

      @josliber,我按照你的建议在重新发布之前编辑了答案。

      【讨论】:

        【解决方案4】:

        除了提到的(并且非常真实的)原因之外,您是否首先验证了foo1 == foo2?当您处理浮点值时,很容易出现差异......

        【讨论】:

          【解决方案5】:

          对于浮点数,1.0+3.3 == 4.3 并不总是 TRUE(在 Python 或其他语言中)。具有相同值的可变对象也可以具有不同的 ID。

          【讨论】:

            【解决方案6】:

            在这种情况下,包含变量的浮点值可能包含相同的数据,但背后的原因是数学规则。 唯一的两个值是在点之后考虑的,剩余的值被忽略。 所以我们得到了包含变量的相同数据的两个不同地址。 为了解决这个错误,我们可以使用 round() 方法。

            y=3.1254
            x = 3.1254
            print(round(x,2))
            print(round(y,2))
            print(id(x)==id(y))
            

            这可以显示两者具有相同的地址,因为在 print(round(x,2)) 方法和 print(round(y,2)) 方法中,点后只有两位数。

            【讨论】:

              猜你喜欢
              • 2010-09-12
              • 2014-06-19
              • 2022-01-25
              • 1970-01-01
              • 2021-05-04
              • 1970-01-01
              • 1970-01-01
              • 2021-05-14
              • 2014-09-27
              相关资源
              最近更新 更多