创建一个看起来像浮点数的类对象

2 投票
3 回答
2677 浏览
提问于 2025-04-18 03:24

我想自己做一个简单的对象,用来跟踪变量的单位(也许我还会添加其他属性,比如公差)。这是我目前的进展:

class newVar():
    def __init__(self,value=0.0,units='unknown'):
        self.value=value
        self.units=units

    def __str__(self):
        return str(self.value) + '(' + self.units + ')'

    def __magicmethodIdontknow__(self): 
        return self.value


diameter=newVar(10.0,'m') #define diameter's value and units

print diameter #printing will print value followed by units

#intention is that I can still do ALL operations of the object
#and they will be performed on the self.value inside the object.

B=diameter*2 

因为我没有正确的魔法方法,所以我得到了以下输出

10.0(m)
Traceback (most recent call last):
  File "C:\Users\user\workspace\pineCar\src\sandBox.py", line 25, in <module>
     B=diameter*2 
TypeError: unsupported operand type(s) for *: 'instance' and 'int'

我想我可以重写每个魔法方法,让它们都返回self.value,但这样做感觉不太对。也许我需要一个装饰器?

另外,我知道我可以直接调用直径的值,但这样似乎有点重复。

3 个回答

0

在Python中,你可以重写很多不同的运算符,其中一些是用来模拟数字类型的。想了解更多,可以点击这里

以乘法为例,你只需要像下面这样重写 __mul__(self, other)

def __mul__(self, other):
    return self.value * other

你还可以重写其他数字运算,比如 __add__(self, other)(用于加法)、__sub__(self, other) 等等。

稍微偏离一下话题,你可能还需要考虑,如果有人想把两个直径相乘或者把一个重量加到直径上,你希望它的行为是什么样的。

更新

根据你的评论,你可能更适合重写对象的浮点数表示,就像约翰提到的那样,虽然这没有重写数学运算符那么干净:

def __float__(self):
    return self.value
0
class newVar():

    def __init__(self,value=0.0,units='unknown'):
        self.value=value
        self.units=units

    def __repr__(self):
        return str(self.value) + '(' + self.units + ')'

    def __mul__(self, other):

        if hasattr(other, "value"):
            return self.value * other.value
        else:
            return self.value * other

diameter=newVar(10.0,'m')

print diameter 
print diameter*2
class newVar():

    def __init__(self,value=0.0,units='unknown'):
        self.value=value
        self.units=units

    def __repr__(self):
        return str(self.value) + '(' + self.units + ')'

    def __float__(self):

        return self.value

diameter=newVar(10.0,'m')

print diameter 
print float(diameter)*2

另一种可能的解决办法是重写对象的浮点数表示方式。

5

我曾经尝试自己实现类似的东西,但一直没能完成。有一种方法是从头开始创建一个新类,这个类同时包含数值和单位。不过,如果你想在计算中使用它,就必须实现一些特殊的方法,比如 __add____mul__,这些方法负责处理加法和乘法运算。另一种方法是直接继承 float 类:

class FloatWithUnit(float):
    def __new__(cls, val, unit):
        return float.__new__(cls, val)
    def __init__(self, val, unit):
        self.unit = unit
    def __str__(self):  
        return '%g %s' % (self, self.unit)
    def __repr__(self):
        return self.__str__()

继承 float 类显然有点棘手,所以除了 __init__ 方法外,你还需要实现 __new__ 方法,具体讨论可以参考 这里。当你在命令行输入这样的对象时,它会显示它的单位:

In [2]: g = FloatWithUnit(9.81, 'm/s^2')

In [3]: g
Out[3]: 9.81 m/s^2

In [4]: type(g)
Out[4]: __main__.FloatWithUnit

但是在计算时,它的表现就像一个普通的 float 一样。

In [5]: g2 = 2 * g

In [6]: g2
Out[6]: 19.62

In [7]: type(g2)
Out[7]: float

撰写回答