Subclassing Decimal in Python -
i want use decimal class in python program doing financial calculations. decimals not work floats - need explicit conversion strings first. decided subclass decimal able work floats without explicit conversions.
m_decimal.py:
# -*- coding: utf-8 -*- import decimal decimal = decimal.decimal def floatcheck ( obj ) : # decimal not work floats return repr ( obj ) if isinstance ( obj, float ) else obj # automatically converts floats decimal class m_decimal ( decimal ) : __integral = decimal ( 1 ) def __new__ ( cls, value = 0 ) : return decimal.__new__ ( cls, floatcheck ( value ) ) def __str__ ( self ) : return str ( self.quantize ( self.__integral ) if self == self.to_integral () else self.normalize () ) # http://docs.python.org/library/decimal.html#decimal-faq def __mul__ ( self, other ) : print (type(other)) decimal.__mul__ ( self, other ) d = m_decimal print ( d(5000000)*d(2.2))
so instead of writing d(5000000)*d(2.2)
should able write d(5000000)*2.2
without rasing exceptions.
i have several questions:
will decision cause me troubles?
reimplementing
__mul__
doesn't work in case ofd(5000000)*d(2.2)
, because other argument of typeclass '__main__.m_decimal'
, can see in decimal module this:
decimal.py, line 5292:
def _convert_other(other, raiseit=false): """convert other decimal. verifies it's ok use in implicit construction. """ if isinstance(other, decimal): return other if isinstance(other, (int, long)): return decimal(other) if raiseit: raise typeerror("unable convert %s decimal" % other) return notimplemented
the decimal module expects argument being decimal or int. means should convert m_decimal object string first, decimal. lot of waste - m_decimal descendant of decimal - how can use make class faster (decimal slow).
- when cdecimal appear, subclassing work?
currently, won't want @ all. can't multiply m_decimal anything: return none, due missing return statement:
def __mul__ ( self, other ) : print (type(other)) return decimal.__mul__ ( self, other )
even return added in, still can't d(500000)*2.2, float still needs converting decimal, before decimal.mul accept it. also, repr not appropriate here:
>>> repr(2.1) '2.1000000000000001' >>> str(2.1) '2.1'
the way it, make classmethod, fromfloat
@classmethod def fromfloat(cls, f): return cls(str(f))
then override mul method check type of other, , run m_decimal.fromfloat() on if float:
class m_decimal(decimal): @classmethod def fromfloat(cls, f): return cls(str(f)) def __mul__(self, other): if isinstance(other, float): other = m_decimal.fromfloat(other) return decimal.__mul__(self,other)
it work expect. wouldn't override new method, seems cleaner me use fromfloat() method. that's opinion.
like dirk said, don't need worry conversion, isinstance works subclasses. problem might have decimal*m_decimal return decimal, rather subclass:
>>> decimal(2) * m_decimal(2) * 2.2 traceback (most recent call last): file "<pyshell#3>", line 1, in <module> decimal(2) * m_decimal(2) * 2.2 typeerror: unsupported operand type(s) *: 'decimal' , 'float'
there 2 ways fix this. first add explicit conversion m_decimal's mul magicmethod:
def __mul__(self, other): if isinstance(other, float): other = m_decimal.fromfloat(other) return m_decimal(decimal.__mul__(self,other))
the other way, wouldn't recommend, "monkeypatch" decimal module:
decimal._decimal = decimal.decimal decimal.decimal = m_decimal
Comments
Post a Comment