如何正确使用派生的不可变类?

2024-04-27 13:46:36 发布

您现在位置:Python中文网/ 问答频道 /正文

我在使用内置类型float的派生类编写简单的单元转换器时遇到了一些困难。你知道吗

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

  • 模式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,因为self现在只是一个普通的浮点。我想我应该定义一个覆盖代数运算符的函数,这样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

Tags: 实例selftargetdefnpcmunitarray
1条回答
网友
1楼 · 发布于 2024-04-27 13:46:36

您需要__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)

相关问题 更多 >