使用内置类型float
的派生类编写一个简单的单位转换器时遇到了一些困难。
尝试1:
我尝试返回实例的新副本,而不是change the state of it
。但是,我无法理解。
参见2
我尝试更改self
的值,但它会销毁atrribute 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
答案 0 :(得分: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)