类继承 - 是否可以将所有继承的方法转换为子类类型?

时间:2018-02-28 10:20:42

标签: python python-3.x class inheritance

假设我想创建自己的现有类版本。我们选择内置的float类。在这个例子中,我将创建一个像类一样的浮点数,当除以零时不会引发错误,而是返回字符串'inf'(请记住这只是一个例子。避免除零错误不是这个的主要观点问题)。

class myfloat(float):
    def __truediv__(self, b):
        if b == 0:
            return 'inf'
        else:
            return myfloat(self.__float__() / b)

当除法与int或float结合使用时也适用。

In[88]: a = myfloat(10)
In[89]: a / 2
Out[89]: 5.0
In[90]: a / 0
Out[90]: 'inf'

但是,由于float类的继承,当我进行任何其他操作(即方法)时,结果将是一个浮点数。例如:

In[92]: b = myfloat(20)
In[93]: (a + b) / 0
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-6-f769cd843514> in <module>()
----> 1 (a + b) / 0

ZeroDivisionError: float division by zero

加法方法仍然不会改变从父浮点类继承的加法方法,显然会返回一个浮点数。

所以我的问题:是否有一种巧妙的方法可以让子类中的所有继承方法返回子类中的结果,而无需重写所有方法?我正在考虑将装饰器@myfloat自动应用于所有(适用的)继承方法,以将其结果从类型float转换为类型myfloat

1 个答案:

答案 0 :(得分:1)

这是一种装饰器的方法,它可以减少每个需要进行类型转换的方法的单行操作。它甚至包含@Graipher的self.__class__提示,这使得装饰工作无需更改就可以在某一天重命名myfloat

def cast_return(func):
    """ Decorator that casts the return value of a special __method__
        back to the original type of 'self'. """
    def wrapped(self, *args, **kwargs):
        return self.__class__(func(self, *args, **kwargs))
    return wrapped

class myfloat(float):
    def __truediv__(self, b):
        if b == 0:
            return 'inf'
        else:
            return myfloat(self.__float__() / b)

    __mul__ = cast_return(float.__mul__)
    __add__ = cast_return(float.__add__)
    # repeat for all the needed operations

然后你得到......

In [1]: (myfloat(3.3) +  4) / 0
Out[1]: 'inf'

有人甚至可以进一步制作这些函数的列表,将它们汇总在一个循环中,但我不认为它们是那么多。

<强>可是:

如果另一种类型处理操作,它仍然无法工作,如下所示:

In [1]:(4 + myfloat(3.3)) / 0
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-45-6537eb18ab79> in <module>()
     16     __add__ = cast_return(float.__add__)
     17 
---> 18 (4 + myfloat(3.3)) / 0

ZeroDivisionError: float division by zero

我真的不知道是否有办法解决这个问题。