7

I would like to extend the Decimal class to add some helpful methods to it, specially for handling money.

The problem when I go do this:

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

It throws an exception:

AttributeError: 'Decimal' object has no attribute 'new_str'

This is because of the way Decimal does arithmetic, it always returns a new Decimal object, by literally calling Decimal(new value) at the end of the computation.
Does anyone no a workaround for this other than completely reimplementing all the arithmetic?

4

2 回答 2

10

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

但你想要的是可行的。


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

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

当然,您也需要覆盖__iadd__。并且不要忘记mul所有其他数字特殊方法

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

注意:如果右操作数的类型是左操作数类型的子类,并且该子类为操作提供了反射方法,则该方法将在左操作数的非反射方法之前调用。此行为允许子类覆盖其祖先的操作。


您可能想阅读模块文档中的实现算术运算部分,以及(旨在用作创建新数字类型的示例代码,这就是文档直接链接到源代码的原因)的实现。您的生活比's 更容易,因为您可以有效地回退到每个操作然后转换(因为与 没有任何不同的数字行为),但值得查看所有问题,并了解哪些是和不是相关的以及为什么。numbersfractions.FractionFractionDecimalNewDecimalDecimal

于 2013-08-09T21:09:06.903 回答
1

你想要的快速方法是这样的:

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

    def __add__(self,b):
        return NewDecimal( Decimal.__add__(self,b) )


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

d2 = NewDecimal(2)
d3 = NewDecimal(3)
d5 = d2 + d3
print d5

> $5
于 2013-08-09T20:22:51.053 回答