gpt4 book ai didi

python - 在 Python 中子类化 Decimal

转载 作者:太空宇宙 更新时间:2023-11-03 10:47:35 25 4
gpt4 key购买 nike

我想在我的 Python 程序中使用 Decimal 类来进行财务计算。小数不适用于 float ——它们首先需要显式转换为字符串。所以我决定将 Decimal 子类化,以便能够在没有显式转换的情况下使用 float 。

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__D(5000000)*D(2.2) 的情况下不起作用,因为另一个参数是 class 类型'__main__.m_Decimal',但是你可以在 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

decimal 模块期望参数是 Decimal 或 int。这意味着我应该先将我的 m_Decimal 对象转换为字符串,然后再转换为 Decimal。但这是很多浪费 - m_Decimal 是 Decimal 的后代 - 我如何使用它来使类(class)更快(Decimal 已经很慢了)。

  1. 当 cDecimal 出现时,这个子类化会起作用吗?

最佳答案

目前,它根本不会执行您想要的操作。你不能将你的 m_decimal 乘以任何东西:它总是返回 None,因为缺少 return 语句:

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

即使添加了 return,您仍然不能执行 D(500000)*2.2,因为 float 仍需要转换为 Decimal,然后 Decimal.mul 才会接受它。另外,repr 在这里不合适:

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

我的方法是创建一个类方法,fromfloat

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

然后重写 mul 方法来检查 other 的类型,如果它是 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'

有两种方法可以解决这个问题。首先是向 m_Decimal 的 mul magicmethod 添加显式转换:

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

我可能不推荐的另一种方法是“Monkeypatch”十进制模块:

decimal._Decimal = decimal.Decimal
decimal.Decimal = m_Decimal

关于python - 在 Python 中子类化 Decimal,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2044427/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com