在Python中使用从父类继承的方法时,返回子类的新实例

时间:2018-11-03 19:27:42

标签: python inheritance subclass

我想为复杂类型创建一个新的__str__方法。

import numpy as np  

class Phasor(complex):
    def __str__(self):   
        magnitude = (self.real**2 + self.imag**2)**.5
        angle = np.arctan2(self.imag, self.real)
        return "%s ∠ %s°" % (round(magnitude, 2), round(np.degrees(angle), 2))

a = Phasor(1+1j)
print(a)
print(type(a))
print(a**2)
print(type(a**2))

返回

1.41 ∠ 45.0°
<class '__main__.Phasor'>
2j
<type 'complex'>

在这种情况下,将实例提升为幂将返回复杂类型的实例,而不是子类实例。

我希望继承的方法返回子类的新实例并且不复杂。

1 个答案:

答案 0 :(得分:2)

为了使算术运算符返回子类的实例,您必须实现相关的special methods,例如__add____mul____pow__等。

坏消息是这些方法很多。好消息是您可以编写代码来自动为您生成这些功能。这是一个完全做到这一点的类装饰器:

def add_arithmetic_methods(cls):
    def make_func(func_name):
        def func(self, *args, **kwargs):
            super_method = getattr(super(cls, self), func_name)
            return type(self)(super_method(*args, **kwargs))

        func.__name__ = func_name
        func.__qualname__ = '{}.{}'.format(cls.__qualname__, func_name)
        func.__module__ = cls.__module__

        return func

    for func_name in ['add', 'sub', 'mul', 'matmul', 'truediv', 'floordiv',
                      'mod', 'divmod', 'pow', 'lshift', 'rshift', 'and',
                      'xor', 'or', 'radd', 'rsub', 'rmul', 'rmatmul',
                      'rtruediv', 'rfloordiv', 'rmod', 'rdivmod', 'rpow',
                      'rlshift', 'rrshift', 'rand', 'rxor', 'ror', 'iadd',
                      'isub', 'imul', 'imatmul', 'itruediv', 'ifloordiv',
                      'imod', 'ipow', 'ilshift', 'irshift', 'iand', 'ixor',
                      'ior', 'neg', 'pos', 'abs', 'invert']:
        func_name = '__{}__'.format(func_name)
        func = make_func(func_name)
        setattr(cls, func_name, func)

    return cls

将其拍到您的Phasor类上,您就可以完成:

@add_arithmetic_methods
class Phasor(complex):
    def __str__(self):   
        magnitude = (self.real**2 + self.imag**2)**.5
        angle = np.arctan2(self.imag, self.real)
        return "%s ∠ %s°" % (round(magnitude, 2), round(np.degrees(angle), 2))

c = Phasor(3+5j)
print(c**2)
# output: 34.0 ∠ 118.07°