从前一个问题跳出来,我问了一会儿:
Why is 1000000000000000 in range(1000000000000001) so fast in Python 3?
如果你这样做:
1000000000000000.0 in range(1000000000000001)
...很明显range
尚未优化以检查float
是否在指定范围内。
我认为我理解range
的目的只是与int
合作 - 所以你不能,例如,做这样的事情:
1000000000000 in range(1000000000000001.0)
# error: float object cannot be interpreted as an integer
或者这个:
1000000000000 in range(0, 1000000000000001, 1.0)
# error: float object cannot be interpreted as an integer
然而,无论出于何种原因,决定允许这样的事情:
1.0 in range(1)
很明显,1.0
(以及1000000000000.0
以上)未被强制转换为int
,因为int
优化也适用于那些人。
我的问题是,为什么不一致,以及为什么没有优化float
?或者,或者,为什么上述代码不会产生与前面示例相同的错误的原因是什么?
除了优化int
之外,这似乎是一个明显的优化。我猜测有一些细微的问题妨碍了这种优化的干净实施,或者有一些理由说明为什么你实际上不想包含这样的优化。或者两者都可能。
编辑:为了澄清这个问题,以下所有语句也评估为False
:
3.2 in range(5)
'' in range(1)
[] in range(1)
None in range(1)
这对我来说似乎是出乎意料的行为,但到目前为止肯定没有不一致。但是,以下评估为True
:
1.0 in range(2.0)
如前所示,与上述类似的结构尚未优化。
这似乎不一致 - 在评估的某个时刻,1.0
(或我原始示例中的1000000000001.0
)被强制转换为int
。这是有道理的,因为将float
中的.0
结尾转换为int
是很自然的事情。但是,问题仍然存在:如果转换为int
,为什么1000000000000.0 in range(1000000000001)
未被优化?
答案 0 :(得分:5)
此处无不一致。浮点值不能被强制转换为整数,只能以相反的方式工作。因此,range()
在测试遏制时不会隐式地将浮点数转换为整数。
range()
对象是序列类型;它包含离散的整数值(尽管是虚拟的)。因此,它必须支持任何对象的包含测试,该对象可能测试相同。以下也适用:
>>> class ThreeReally:
... def __eq__(self, other):
... return other == 3
...
>>> ThreeReally() in range(4)
True
这必须对范围内的所有可能值进行全面扫描,以测试与每个包含的整数的相等性。
但是,只有在使用实际整数时才能应用优化,因为这是range()
对象可以知道的唯一类型如果没有转换,价值将被视为相等。