__add__ возвращает экземпляр суперкласса, а не подкласса - PullRequest
2 голосов
/ 21 апреля 2020

Когда я делаю подкласс некоторого класса, скажем int, и настраиваю его __add__ метод и вызываю super().__add__(other), он возвращает экземпляр int, а не мой подкласс. Я мог бы исправить это, добавив type(self) перед каждым super() вызовом в каждом методе, который возвращает int, но это кажется чрезмерным. Должен быть лучший способ сделать это. То же самое происходит с floats и fractions.Fraction с.

class A(int):
    def __add__(self, other):
        return super().__add__(other)

x = A()
print(type(x + 1))

Вывод: <class 'int'>

Ожидаемый результат: <class '__main__.A'>

Ответы [ 3 ]

2 голосов
/ 21 апреля 2020

Это можно сделать с помощью дескриптора . В следующем классе используются специальные методы, которые имеют особый эффект, когда этот класс создается в теле класса.

class SuperCaller:

    def __set_name__(self, owner, name):
        """Called when the class is defined. owner is the class that's being
        defined. name is the name of the method that's being defined.
        """
        method = getattr(super(owner, owner), name)
        def call(self, other):
            # Note that this self shadows the __set_name__ self. They are two
            # different things.
            return type(self)(method(self, other))
        self._call = call

    def __get__(self, instance, owner):
        """instance is an instance of owner."""
        return lambda other: self._call(instance, other)


class A(int):
    __add__ = SuperCaller()


x = A()
print(type(x + 1))

Вывод: <class '__main__.A'>

1 голос
/ 21 апреля 2020

Один из подходов состоит в том, чтобы создать декоратор, который мог бы обернуть нужные математические операции с помощью приведения:

def wrap_math(c):
    def wrapped(orig):
        return lambda s, o: c(orig(s,o))

    maths = ["__add__", "__sub__"]
    for op in maths:
        func = wrapped(getattr(c, op))
        setattr(c, op, func)

return c

@wrap_math
class Special(int)
    pass

 x = Special(10)
 type(x + 10)

Заполните список функций, которые вы хотите обернуть, и у вас должно получиться go.

0 голосов
/ 21 апреля 2020

функция super() вызывает метод из родительского класса, в данном случае int. Вместо этого вы должны инициализировать класс в методе __add__:

class A(int):
    def __add__(self, number):
        return A(self.numerator + number)

x = A(4)
print(type(x + 1))
...