为啥在 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 显式检查操作数的longintDecimal 类型。对,这就是 一个错误,因为意外的库实现会进一步导致错误。它 做正确的事甚至只是通过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),因此结果仅取决于floatDecimal 类型的内存地址(这解释了平台差异)。血淋淋的细节在 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 为真?的主要内容,如果未能解决你的问题,请参考以下文章

python decimal库如何删除后面无用的0?

为啥 Decimal.Divide(int, int) 有效,但 (int / int) 无效?

Java 为啥不提供decimal

为啥 OleDb ExecuteScalar 方法在查询 COUNT 时返回 Decimal?

将string类型转换为decimal为啥会自动四舍五入

mysql字段类型为decimal,则java 实体类的对应属性类型应该为啥