为啥在 Python 中 Decimal('0') > 9999.0 为真?
Posted
技术标签:
【中文标题】为啥在 Python 中 Decimal(\'0\') > 9999.0 为真?【英文标题】:Why is Decimal('0') > 9999.0 True in Python?为什么在 Python 中 Decimal('0') > 9999.0 为真? 【发布时间】:2011-01-26 15:12:10 【问题描述】:这在某种程度上与我的问题Why is ''>0 True in Python?
有关在 Python 2.6.4 中:
>> Decimal('0') > 9999.0
True
从answer 到我最初的问题,我了解到,在比较 Python 2.x 中不同类型的对象时,类型按名称排序。但在这种情况下:
>> type(Decimal('0')).__name__ > type(9999.0).__name__
False
那为什么是Decimal('0') > 9999.0 == True
?
更新:我通常在 Ubuntu 上工作(Linux 2.6.31-20-generic #57-Ubuntu SMP Mon Feb 8 09:05:19 UTC 2010 i686 GNU/Linux, Python 2.6.4 (r264:75706, Dec 7 2009, 18:45:15) [GCC 4.4.1] on linux2)。在 Windows 上(WinXP Professional SP3, Python 2.6.4 (r264:75706, Nov 3 2009, 13:23:17) [MSC v.1500 32 bit (Intel)] on win32)我原来的说法不同:
>> Decimal('0') > 9999.0
False
我现在更疑惑了。 %-(
【问题讨论】:
我没有得到与您的第一个语句相同的结果。在我看来,它是假的。不过,对于您的第二个陈述,我确实得到了相同的结果。我也在使用 Python 2.6.4。 @Justin 这让我更加困惑,因为我检查了三次,它确实返回了True
使用python 3.1.1,第一条语句给出(导入Decimal后):TypeError: unorderable types: Decimal() > float()
@Justin 我再次检查了 Windows 框,它返回了 False
%-(
好吧,至少你已经学会了在生产代码中不要依赖这种类型的东西:)
【参考方案1】:
因为 decimal 模块不与除 long、int 和 Decimal 之外的任何类型进行比较。在所有其他情况下,十进制会默默地返回“它不知道关于对象的东西”作为更大的值。您可以在 decimal.py 的 _convert_other() 函数中看到这种行为
傻,傻 Decimal 类。
哦,也见http://bugs.python.org/issue2531。
所以,这就是发生的事情:
解释器调用Decimal.__gt__
比较函数。
Decimal.__gt__
调用 Decimal._convert_other
将传入的浮点数转换为十进制。
Decimal._convert_other
不懂浮点数。实现在Decimal._convert_other
显式检查操作数的long
、int
和Decimal
类型。对,这就是
一个错误,因为意外的库实现会进一步导致错误。它
做正确的事甚至只是通过TypeException
会更干净。反而
它通过相同的NotImplemented
,将 Decimal 与例如,
员工记录的哈希。
尝试了其他一些比较操作。比较放弃。
默认比较,在 CPython 的 Objects/object.c/default_3way_compare 中被调用。
在 Python 3 中,这是正确的。在 Python 2 中,它比较 id() 函数。
在 Windows 上,使用不区分大小写的比较(有点)。在现代系统中,
使用区分大小写的比较。
因此您会得到不同的结果。
我们到了吗?
【讨论】:
Tx 让我正确,所以我删除了我的(误导性)答案,并 +1 表示感谢;-)。 @charles:为什么它在不同平台上的工作方式不同? 没有线索。我没有窗户。尝试在两者上拉出 _convert_other() 并进行比较。 @Charles Merram:这不太对。十进制不会返回更大的“它不知道对象的东西”:它返回NotImplemented
。由于比较的浮点侧也返回NotImplemented
,当两个操作数都不知道如何与另一个比较时,Python 会回退到它应用的默认规则;这最终有效地比较了id(float)
和id(Decimal)
,因此结果仅取决于float
和Decimal
类型的内存地址(这解释了平台差异)。血淋淋的细节在 Objects/object.c 中的 default_3way_compare
中。
嗯..听起来很合理,我会看看。【参考方案2】:
def __gt__(self, other, context=None):
other = _convert_other(other)
if other is NotImplemented:
return other
ans = self._compare_check_nans(other, context)
if ans:
return False
return self._cmp(other) > 0
def _convert_other(other, raiseit=False):
"""Convert other to Decimal.
Verifies that it's ok to use in an implicit construction.
"""
if isinstance(other, Decimal):
return other
if isinstance(other, (int, long)):
return Decimal(other)
if raiseit:
raise TypeError("Unable to convert %s to Decimal" % other)
return NotImplemented
【讨论】:
以上是关于为啥在 Python 中 Decimal('0') > 9999.0 为真?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Decimal.Divide(int, int) 有效,但 (int / int) 无效?