2010-07-07 105 views
1

我不清楚如何提出这个问题。如果我这样做,我可能会更接近解决方案..我需要一些洞察继承。我想制作一个自定义子类型float。但是我希望这个子类型的实例在执行任何正常浮点方法(__add__,__mul__等)之前重新评估它的值。在这个例子中,应该由全球要素乘以它的价值:Python中的继承示例

class FactorFloat(float): 
    # I don't think I want to do this: 
    ## def __new__(self, value): 
    ##  return float.__new__(self, value) 
    def __init__(self, value): 
     float.__init__(self, value) 
    # Something important is missing.. 
    # I want to do something with global FACTOR 
    # when any float method is called. 

f = FactorFloat(3.) 
FACTOR = 10. 
print f # 30.0 
print f-1 # 29.0 
FACTOR = 2. 
print f # 6.0 
print f-1 # 5.0 

这是一刚一消毒的例子,我觉得整个得到我的观点。如有必要,我会发布更复杂的“真实”问题。

回答

5
class FactorFloat(float): 
    def _factor_scale(f): 
     def wrapper(self, *args, **kwargs): 
      scaled = float.__mul__(self, FACTOR) 
      result = f(scaled, *args, **kwargs) 
      # if you want to return FactorFloats when possible: 
      if isinstance(result, float): 
       result = type(self)(result/FACTOR) 
      return result 
     return wrapper 

    def __repr__(self): 
     return '%s(%s)' % (type(self).__name__, float.__repr__(self)) 

    __str__ = _factor_scale(float.__str__) 
    __mul__ = _factor_scale(float.__mul__) 
    __div__ = _factor_scale(float.__div__) 
    __add__ = _factor_scale(float.__add__) 
    __sub__ = _factor_scale(float.__sub__) 


f = FactorFloat(3.) 
FACTOR = 10. 
print f # 30.0 
print f-1 # 29.0 
FACTOR = 2. 
print f # 6.0 
print f-1 # 5.0 
print repr(f) 

为:

30.0 
29.0 
6.0 
5.0 
FactorFloat(3.0) 

编辑:

针对在评论的问题;使用类装饰器使事情变得更加通用和自动化。我不会循环使用dir(baseclass),而是会明确列出我希望包装的方法。在下面的例子中,我将它们列在类变量_scale_methods中。

def wrap_scale_methods(cls): 
    Base = cls.__base__ 
    def factor_scale(f): 
     def wrapper(self, *args, **kwargs): 
      scaled = Base.__mul__(self, FACTOR) 
      result = f(scaled, *args, **kwargs) 
      if isinstance(result, Base): 
       result = type(self)(result/FACTOR) 
      return result 
     return wrapper 
    for methodname in cls._scale_methods: 
     setattr(cls, methodname, factor_scale(getattr(Base, methodname))) 
    return cls 

@wrap_scale_methods 
class FactorComplex(complex): 
    _scale_methods = '__str__ __mul__ __div__ __add__ __sub__'.split() 
    def __repr__(self): 
     return '%s(%s)' % (type(self).__name__, complex.__repr__(self)[1:-1]) 
+0

谢谢。只是好奇,有没有一种方法可以循环使用dir(float)而不是单独定义'__mul__','__div__'等?我问,因为我可能想尝试一个numpy数组而不是浮动。 – Paul 2010-07-10 19:30:15

+0

请参阅编辑我的答案。 – 2010-07-10 20:45:25

1

你想要做的事实际上很难。我不知道任何Python类型的子类,如floatint,然后用它进行数学计算。我认为,也许有更好的方法来完成你想要实现的目标,而不使用float的子类。你应该研究替代方案。

1

这里有一些方法让你的测试用例传递

def __str__(self): 
    return str(FACTOR*self) 
def __sub__(self, other): 
    return self*FACTOR-other 

很明显,你也必须实现__add____mul__,等...

话虽如此 - 你有什么用呢?这似乎是一个奇怪的事情想要做

+0

我的用例是使用一些全局查找值的多轴插值。例如,我想将空气密度定义为一个简单的浮点变量,它取决于全球压力和温度。但是,我还想交换使用实际浮子来获得与温度和/或压力无关的密度(例如钢)。我希望避免实现__add__,__mul__等,但似乎不可避免。 ..和可能比发布这个问题更容易.. – Paul 2010-07-07 05:51:20