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:

  1. will decision cause me troubles?

  2. reimplementing __mul__ doesn't work in case of d(5000000)*d(2.2), because other argument of type class '__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).

  1. 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

Popular posts from this blog

c++ - Convert big endian to little endian when reading from a binary file -

C#: Application without a window or taskbar item (background app) that can still use Console.WriteLine() -

unicode - Are email addresses allowed to contain non-alphanumeric characters? -