“is"运算符对浮点数的行为出乎意料 [英] 'is' operator behaves unexpectedly with floats

查看:16
本文介绍了“is"运算符对浮点数的行为出乎意料的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在对模块进行单元测试时遇到了一个令人困惑的问题.该模块实际上正在转换值,我想比较这些值.

==is相比有区别(部分,我提防区别)

<预><代码>>>>0.0 是 0.0True # 符合预期>>>浮动(0.0)是0.0True # 符合预期

到目前为止,正如预期的那样,但这是我的问题":

<预><代码>>>>浮动(0)是0.0错误的>>>浮动(0)是浮动(0)错误的

为什么?至少最后一个让我很困惑.float(0)float(0.0) 的内部表示应该是相等的.与 == 的比较按预期工作.

解决方案

这与 is 的工作方式有关.它检查引用而不是值.如果任一参数分配给同一个对象,则返回 True.

在这种情况下,它们是不同的实例;float(0)float(0) 具有相同的值 ==,但就 Python 而言是不同的实体.CPython 实现还将整数缓存为此范围内的单例对象 -> [x |x ∈ ℤ ∧ -5 ≤ x ≤ 256 ]:

<预><代码>>>>0.0 是 0.0真的>>>float(0) is float(0) # 不一样的引用,唯一的实例.错误的

在这个例子中我们可以演示整数缓存原理:

<预><代码>>>>一 = 256>>>乙 = 256>>>a 是 b真的>>>一 = 257>>>乙 = 257>>>a 是 b错误的

现在,如果将浮点数传递给 float(),则简单地返回浮点字面量(短路),因为在同一引用中使用,因为有无需从现有浮点数实例化新浮点数:

<预><代码>>>>0.0 是 0.0真的>>>浮动(0.0)是浮动(0.0)真的

这也可以通过使用 int() 进一步证明:

<预><代码>>>>int(256.0) is int(256.0) # 相同的引用,缓存.真的>>>int(257.0) is int(257.0) # 返回不同的引用,不缓存.错误的>>>257 是 257 # 相同的引用.真的>>>257.0 是 257.0 # 相同的引用.正如@Martijn Pieters 指出的那样.真的

然而,is 的结果也取决于它正在执行的范围(超出这个问题/解释的范围),请参考用户:@Jim代码对象.甚至 python 的文档也包含有关此行​​为的部分:

<块引用>

[7]由于自动垃圾收集、空闲列表和描述符的动态特性,您可能会注意到在 is 运算符的某些使用中看似异常的行为,例如涉及实例方法或常量之间的比较的行为.查看他们的文档以了解更多信息.

I came across a confusing problem when unit testing a module. The module is actually casting values and I want to compare this values.

There is a difference in comparison with == and is (partly, I'm beware of the difference)

>>> 0.0 is 0.0
True   # as expected
>>> float(0.0) is 0.0
True   # as expected

As expected till now, but here is my "problem":

>>> float(0) is 0.0
False
>>> float(0) is float(0)
False

Why? At least the last one is really confusing to me. The internal representation of float(0) and float(0.0) should be equal. Comparison with == is working as expected.

解决方案

This has to do with how is works. It checks for references instead of value. It returns True if either argument is assigned to the same object.

In this case, they are different instances; float(0) and float(0) have the same value ==, but are distinct entities as far as Python is concerned. CPython implementation also caches integers as singleton objects in this range -> [x | x ∈ ℤ ∧ -5 ≤ x ≤ 256 ]:

>>> 0.0 is 0.0
True
>>> float(0) is float(0)  # Not the same reference, unique instances.
False

In this example we can demonstrate the integer caching principle:

>>> a = 256
>>> b = 256
>>> a is b
True
>>> a = 257
>>> b = 257
>>> a is b
False

Now, if floats are passed to float(), the float literal is simply returned (short-circuited), as in the same reference is used, as there's no need to instantiate a new float from an existing float:

>>> 0.0 is 0.0
True
>>> float(0.0) is float(0.0)
True

This can be demonstrated further by using int() also:

>>> int(256.0) is int(256.0)  # Same reference, cached.
True
>>> int(257.0) is int(257.0)  # Different references are returned, not cached.
False
>>> 257 is 257  # Same reference.
True
>>> 257.0 is 257.0  # Same reference. As @Martijn Pieters pointed out.
True

However, the results of is are also dependant on the scope it is being executed in (beyond the span of this question/explanation), please refer to user: @Jim's fantastic explanation on code objects. Even python's doc includes a section on this behavior:

[7] Due to automatic garbage-collection, free lists, and the dynamic nature of descriptors, you may notice seemingly unusual behaviour in certain uses of the is operator, like those involving comparisons between instance methods, or constants. Check their documentation for more info.

这篇关于“is"运算符对浮点数的行为出乎意料的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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