Reputation: 330
I'm trying to inherit Decimal and create a math class than can handle polymorphic input. The problem I'm running into is that nothing I do seems to allow me to create duplicate instances.
I've looked at dozens of examples, but nothing I've found actually creates multiple instances from an internal constructor. They all do it from outside.
To have overridden math functions with polymorphic input, the instance-constructor MUST be internal to the class. There is no other way. I've been over this ten different ways, looked at tons of online docs ( mostly flat out wrong ) Hopefully somebody here can help.
#### FOO.py
import sys
from decimal import Decimal, getcontext
import socket
import operator
import re
import copy
class Amount(Decimal):
def __init__(self):
instancehex = hex(id(self))
print ("class: ", self.__class__.__name__)
print ("baseclass: ", self.__class__.__base__)
print ("instance: ", instancehex)
super(type(self),self).__init__() # inherit decimal for getcontext()
print ("postinitclass: ", self.__class__.__name__)
print ("postinitbaseclass: ", self.__class__.__base__)
print ("postinitinstance: ", instancehex)
# these are instance variables? If not, how from inside an instance-constructor?
self.value = Decimal(0.0) # our initial value
self.isdefined = False #
def newamount(self, *arg):
# this should call __init__? Doesn't happen.
thisobject = copy.deepcopy(self)
# these should be different memory addresses?
selfhex = hex(id(self))
thishex = hex(id(thisobject))
print ("\tself: ", str(selfhex))
print ("\tcopy: ", str(thishex))
if len(arg):
polyinput = arg[0]
thisobject.setvalue(polyinput)
self.isdefined = True
return(thisobject)
def setvalue(self,polyinput):
# polymorphic numeracy
print ("\t\tsetting from: ", polyinput.__class__.__name__)
if polyinput.__class__.__name__ == "Amount":
self.value = (polyinput.value)
elif polyinput.__class__.__name__ == "float":
self.value.from_float(polyinput)
def __add__(self,polyinput):
rcvamount = self.newamount(polyinput)
sumamount = self.newamount()
print ("ADDING:")
if rcvamount.isdefined and self.isdefined:
print ("\tdefined values", str(self.value), ":", str(rcvamount.value))
# super() is magical with operator intercepts?
sumamount.value = self.value + rcvamount.value
else:
assert False, "cannot add undefined values"
return (sumamount)
#
### testfoo.py
import sys
from decimal import Decimal,getcontext
import socket
import operator
import re
import FOO
# set the class currency type
Factory = FOO.Amount()
print ("Amounts: ")
m0 = Factory.newamount(0.1)
m1 = Factory.newamount(0.02)
m2 = Factory.newamount(0.03)
print ("REPORT: ", m0.__class__, type(m0).__name__, hex(id(m0)), m0)
print ("REPORT: ", m1.__class__, type(m1).__name__, hex(id(m0)), m1)
print ("REPORT: ", m2.__class__, type(m2).__name__, hex(id(m0)), m2)
m3 = m2 + m1
print (type(m3).__name__, hex(id(m3)), m3)
print (m1,":", m2)
print (m1,":",m2,":",m3)
#
class: Amount
baseclass: <class 'decimal.Decimal'>
instance: 0x7f821c830ca8
postinitclass: Amount
postinitbaseclass: <class 'decimal.Decimal'>
postinitinstance: 0x7f821c830ca8
Amounts:
self: 0x7f821c830ca8
copy: 0x7f821c830ca8
setting from: float
self: 0x7f821c830ca8
copy: 0x7f821c830ca8
setting from: float
self: 0x7f821c830ca8
copy: 0x7f821c830ca8
setting from: float
REPORT: <class 'FOO.Amount'> Amount 0x7f821c830ca8 0
REPORT: <class 'FOO.Amount'> Amount 0x7f821c830ca8 0
REPORT: <class 'FOO.Amount'> Amount 0x7f821c830ca8 0
self: 0x7f821c830ca8
copy: 0x7f821c830ca8
setting from: Amount
self: 0x7f821c830ca8
copy: 0x7f821c830ca8
ADDING:
defined values 0 : 0
Amount 0x7f821c830ca8 0
0 : 0
0 : 0 : 0
Upvotes: 0
Views: 63
Reputation: 36623
I believe you are going about this the wrong way. You have effectively created a copy of the __init__
method in newamount
. You would be better off subclassing Decimal
and then just overloading the methods you want to use.
For example, you can create a method to check the type of another object and pass it to Amount
if it is not an instance of Decimal
. Then overloading the __add__
and __radd__
methods allows the Amount
object accept polymorphic addition.
from collections.abc import Iterable
from decimal import Decimal
class Amount(Decimal):
def __repr__(self):
return "Amount({})".format(self.__float__())
def _checkset(self, other):
if isinstance(other, Decimal):
return other
if isinstance(other, Iterable):
return Amount(other[0])
return Amount(other)
def __add__(self, other):
return self.__class__(super().__add__(self._checkset(other)))
def __radd__(self, other):
return self + other
a = Amount(1.2)
a + .4
# returns:
Amount(1.5999999999999999)
1 + a
# returns:
Amount(2.2)
# in your code, iterables only take the first object
a + [2, 3, 4]
# returns:
Amount(3.2)
Upvotes: 1