Возвращать новый экземпляр подкласса при использовании методов, унаследованных от родительского класса в Python - PullRequest
0 голосов
/ 03 ноября 2018

Я хочу создать новый метод __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 голосов
/ 03 ноября 2018

Чтобы арифметические операторы возвращали экземпляр вашего подкласса, вам необходимо реализовать соответствующие специальные методы , такие как __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°
...