0

我在使用内置类型的派生类编写简单的单位转换器时遇到了一些困难float

  • 尝试 1:我尝试返回实例的新副本,而不是change the state of it. 但是,我无法做到这一点。

  • attempl 2 我尝试更改 的值self,但它破坏了属性baseunit,所以AttributeError提出了。

另一件事是我真正想知道的是如何在不丢失类类型的情况下实现代数,例如a = Unit(km/s, 1) * 10返回 Unit 的实例print a # 10 km/s而不是 float 10.0。所以我可以使用 进一步转换它a.to('m/s'),然后print a # 1e4 m/s

谢谢我提前!

编辑

我根据您的建议修改了我的代码,并正确使用了new。它部分有效,因为我可以获得类 Unit 的转换实例并将其传递给变量。这有点够了。但是,有没有一种方法可以在现场进行更改,即让返回的实例替换我原来的实例?

再说一次,如果我尝试以另一种方式开展业务,即

    self /= self.conv[target]
    self.baseunit = target

它抛出 AttributeError 因为selfnow 只是一个普通的浮点数。我想我应该定义一个覆盖代数运算符的函数,这样baseunit就不会丢失。但是如何?


代码:

from __future__ import division
import numpy as np

class Unit(float):
    """provide a simple unit converter for a given quantity"""

    baseconv = {'length': np.array((1e-10, 1e-6, 1e-2, 1., 1e3),
                                    dtype=[('A', 'f'),
                                        ('um', 'f'),
                                        ('cm', 'f'),
                                        ('m', 'f'),
                                        ('km','f')]),
                'speed': np.array((1e3, 1., 1e-2, 1e-10,),
                                dtype=[('km/s', 'f'),
                                        ('m/s', 'f'),
                                        ('cm/s', 'f'),
                                        ('A/s', 'f')]),
                '1': np.array((1.,), dtype=[('1','f')])}

    baseunit = None

    def __new__(self, baseunit='1',num=1.):

        return super(Unit,self).__new__(self, num)

    def __init__(self, baseunit='1', num=1.):
        """set up base unit"""

        self.baseunit = baseunit

        for _key,_val in self.baseconv.items():
            if baseunit in _val.dtype.names:
                utype = _key
                break
        else:
            raise TypeError('Unit not defined: {:s}'.format(baseunit))
        self.conv = np.array(tuple(np.array(self.baseconv[utype].tolist())
                                / self.baseconv[utype][baseunit]),
                            dtype=self.baseconv[utype].dtype)

    def __str__(self,):

        return '{:e} {:s}'.format(self, self.baseunit)

    def to(self,target):

        if target in self.conv.dtype.names:

            return Unit(target, self / self.conv[target]) ! not work


        else:
            raise TypeError('Invalid converter: {:s}->{:s}'
                            .format(self.baseunit, target))


if __name__=='__main__':
    u_test = Unit('km/s')
    print u_test   # 1.0000 km/s
    u_conv = u_test.to('cm/s')
    print u_conv  # 1e5 cm/s
    print u_test  # 1.000 km/s
4

1 回答 1

1

您需要__new__创建(并返回)实例。不可变部分是num,因此需要将其烘焙到实例化中。

初始化的剩余部分应该留给__init__. 像这样的东西

def __new__(cls, baseunit='1', num=1.):
    return super(Unit, cls).__new__(self, num)

def __init__(self, baseunit='1', num=1.):
    """set up base unit"""

    self.baseunit = baseunit

    for _key,_val in self.baseconv.items():
        if baseunit in _val.dtype.names:
            utype = _key
            break
    else:
        raise TypeError('Unit not defined: {:s}'.format(baseunit))
    self.conv = np.array(tuple(np.array(self.baseconv[utype].tolist())
                            / self.baseconv[utype][baseunit]),
                        dtype=self.baseconv[utype].dtype)
于 2013-07-08T18:24:19.860 回答