4

財務計算を行うためにPythonプログラムでDecimalクラスを使用したいと思います。floatで機能しない小数-最初に文字列に明示的に変換する必要があります。そこで、明示的な変換なしでfloatを操作できるように、Decimalをサブクラス化することにしました。

m_Decimal.py:

# -*- coding: utf-8 -*-
import decimal

Decimal = decimal.Decimal

def floatCheck ( obj ) : # usually Decimal does not work with floats
    return repr ( obj ) if isinstance ( obj, float ) else obj # this automatically converts floats to 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))

だから今、書く代わりに、私は例外を発生させることなくD(5000000)*D(2.2)書くことができるはずです。D(5000000)*2.2

いくつか質問があります。

  1. 私の決定は私に何か問題を引き起こしますか?

  2. 他の引数はタイプであるため、の場合、再実装__mul__は機能しませんが、10進モジュールで次のことを確認できます。D(5000000)*D(2.2)class '__main__.m_Decimal'

decimal.py、行5292:

def _convert_other(other, raiseit=False):
    """Convert other to Decimal.

    Verifies that it's ok to use in an implicit construction.
    """
    if isinstance(other, Decimal):
        return other
    if isinstance(other, (int, long)):
        return Decimal(other)
    if raiseit:
        raise TypeError("Unable to convert %s to Decimal" % other)
    return NotImplemented

10進モジュールは、引数がDecimalまたはintであることを想定しています。これは、m_Decimalオブジェクトを最初に文字列に変換してからDecimalに変換する必要があることを意味します。しかし、これは多くの無駄です-m_DecimalはDecimalの子孫です-これを使用してクラスを高速化するにはどうすればよいですか(Decimalはすでに非常に遅いです)。

  1. cDecimalが表示されるとき、このサブクラス化は機能しますか?
4

3 に答える 3

4

現在、それはあなたが望むことをまったくしません。m_decimalに何かを掛けることはできません。returnステートメントがないため、常にNoneが返されます。

    def __mul__ ( self, other ) :
        print (type(other))
        return Decimal.__mul__ ( self,  other )

リターンを追加しても、フロートは10進数の前に10進数に変換する必要があるため、D(500000)*2.2を実行することはできません。mulはそれを受け入れます。また、reprはここでは適切ではありません:

>>> repr(2.1)
'2.1000000000000001'
>>> str(2.1)
'2.1'

私がそれをする方法は、floatからclassmethodを作ることです

    @classmethod
    def fromfloat(cls, f):
        return cls(str(f))

次に、mulメソッドをオーバーライドして他のタイプをチェックし、floatの場合はm_Decimal.fromfloat()を実行します。

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)

その後、期待どおりに機能します。fromfloat()メソッドを使用する方がクリーンなように思われるため、個人的には新しいメソッドをオーバーライドしません。しかし、それは私の意見です。

Dirkが言ったように、isinstanceはサブクラスで機能するため、変換について心配する必要はありません。発生する可能性がある唯一の問題は、Decimal*m_DecimalがサブクラスではなくDecimalを返すことです。

>>> 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) for *: 'Decimal' and 'float'

これを修正するには2つの方法があります。1つは、m_Decimalのmulmagicmethodに明示的な変換を追加することです。

    def __mul__(self, other):
        if isinstance(other, float):
            other = m_Decimal.fromfloat(other)
        return m_Decimal(Decimal.__mul__(self,other))

もう1つの方法は、おそらくお勧めしませんが、10進モジュールを「モンキーパッチ」することです。

decimal._Decimal = decimal.Decimal
decimal.Decimal = m_Decimal
于 2010-01-11T22:07:19.260 に答える
1

私の意見では、フロートはまったく使用しないでください。フロートは、金融アプリケーションに適したツールではありません。floatを使用している場合は、strまたはDecimalを使用して、精度が失われないようにする必要があります。

例えば。
ユーザー入力、ファイル入力-明らかにstrを使用してDecimalに変換し、数学
データベースを実行します-サポートされている場合はdecimalタイプを使用し、サポートされていない場合は文字列を使用してアプリでDecimalに変換します。

floatの使用を主張する場合、Pythonfloatは他の多くのプラットフォームと同等doubleであることに注意してください。たとえば、floatをデータベースに保存する場合は、データベースフィールドのタイプが次のとおりであることを確認してください。double

于 2010-01-11T23:22:06.157 に答える
0

2.7または3.2のcdecimalまたはdecimal.pyを使用します。それらはすべてfrom_floatクラスメソッドを持っています:


class MyDecimal(Decimal):
    def convert(self, v):
        if isinstance(v, float):
            return Decimal.from_float(v)
        else:
            return Decimal(v)
    def __mul__(self, other):
        other = self.convert(other)
        return self.multiply(other)
于 2010-01-14T00:56:31.627 に答える