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?
Using “%”:- “%” operator is used to format as well as set precision in python. This is similar to “printf” statement in C programming. Using format():- This is yet another way to format the string for setting precision.
2️⃣ f-string Thus, you can use f'{value: . 2f}' to return a string representation of the number up to two decimal places.
Use the round() function to print a float to 6 decimal places, e.g. print(round(my_float, 6)) . The round() function will round the floating-point number to 6 decimal places and will return the result.
You probably don't actually want to do this just to have an extra method for printing Decimal objects in an alternate way. A top-level function or monkeypatched method is a whole lot simpler, and cleaner. Or, alternatively, a Money
class that has a Decimal
member that it delegates arithmetic to.
But what you want is doable.
To make NewDecimal(1) + NewDecimal(2)
return NewDecimal(3)
, you can just override __add__
:
def __add__(self, rhs):
return NewDecimal(super().__add__(rhs))
And of course you'll want to override __iadd__
as well. And don't forget mul
and all the other numeric special methods.
But that still won't help for Decimal(2) + NewDecimal(3)
. To make that work, you need to define NewDecimal.__radd__
. You also need to ensure that NewDecimal.__radd__
will get called instead of Decimal.__add__
, but when you're using inheritance, that's easy, because Python has a rule specifically to make this easy:
Note: If the right operand’s type is a subclass of the left operand’s type and that subclass provides the reflected method for the operation, this method will be called before the left operand’s non-reflected method. This behavior allows subclasses to override their ancestors’ operations.
You may want to read the section Implementing the arithmetic operations in the numbers
module docs, and the implementation of fractions.Fraction
(which was intended to serve as sample code for creating new numeric types, which is why the docs link directly to the source). Your life is easier than Fraction
's because you can effectively fall back to Decimal
for every operation and then convert (since NewDecimal
doesn't have any different numeric behavior from Decimal
), but it's worth seeing all the issues, and understanding which ones are and aren't relevant and why.
The quick way to what you want, would be like this:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With