我想扩展 Decimal 类,为其添加一些有用的方法,特别是用于处理金钱。

当我这样做时的问题:

from decimal import Decimal
class NewDecimal(Decimal):
    def new_str(self):
        return "${}".format(self)

d1 = NewDecimal(1)
print d1.new_str() # prints '$1'

d2 = NewDecimal(2)
d3 = NewDecimal(3)
d5 = d2 + d3
print d5.new_str()   #exception happens here

它引发一个异常:
AttributeError: 'Decimal' object has no attribute 'new_str'

这是因为 Decimal 进行算术的方式,它总是返回一个新的 Decimal 对象,在计算结束时通过字面调用 Decimal(new value)。
除了完全重新实现所有算术之外,还有没有人对此没有解决方法?

最佳答案

您可能实际上不想这样做只是为了有一个额外的方法来以替代方式打印 Decimal 对象。顶层函数或monkeypatched方法要简单得多,也更干净。或者,一个 Money 类具有一个 Decimal 成员,它将算术委托(delegate)给它。

但你想要的是可行的。

要使 NewDecimal(1) + NewDecimal(2) 返回 NewDecimal(3) ,您可以覆盖 __add__ :

def __add__(self, rhs):
    return NewDecimal(super().__add__(rhs))

当然,您还需要覆盖 __iadd__。并且不要忘记 mul 和所有其他 numeric special methods

但这对 Decimal(2) + NewDecimal(3) 仍然无济于事。要使其工作,您需要定义 NewDecimal.__radd__ 。您还需要确保 NewDecimal.__radd__ 将被调用而不是 Decimal.__add__ ,但是当您使用继承时,这很容易,因为 Python 有一个专门用于简化此操作的规则:



您可能需要阅读 numbers 模块文档中的 Implementing the arithmetic operations 部分和 the implementation of fractions.Fraction (它旨在用作创建新数字类型的示例代码,这就是文档直接链接到源代码的原因)。你的生活比 Fraction 更容易,因为你可以有效地回退到 Decimal 的每个操作然后转换(因为 NewDecimal 没有任何与 Decimal 不同的数字行为),但值得查看所有问题,并了解哪些是并且不相关以及为什么。

10-06 05:45