Преобразование дочернего объекта в родительский Python

Есть 2 класса:

class MyClass:
    def A(self):
        print(1)

class YourClass(MyClass):
    def A(self):
        print(2)

Метод A базового класса выводит на консоль число 1. Наследник переопределяет данный метод и выводит на консоль 2. Если в коде создать объект класса YourClass и вызвать у него метод A, то в выводе будет 2:

your_class = YourClass()
your_class.A() # 2

Задача дана следующая: Реализовать преобразование дочернего объекта в родительский. После этого преобразования (не изменяя реализации метода A в классе YourClass) при вызове метода A для объекта класса YourClass, выводить в консоль уже должно не 2, а 1. Т.е. :

your_class = YourClass()
your_class.A() # 1

Помогите пожалуйста решить данную задачу, никак не могу прийти к решению.


Ответы (3 шт):

Автор решения: Xander

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

Но если уж прямо очень хочется изменить класс имеющегося объекта, то так:

class MyClass:
    def A(self):
        print(1)

class YourClass(MyClass):
    def A(self):
        print(2)


your_class = YourClass()
your_class.A()  # 2

your_class.__class__ = MyClass
your_class.A()  # 1

Только сразу предупреждаю, что это очень тёмная магия, чреватая разными спецэффектами и в реальном коде так делать не стоит.

→ Ссылка
Автор решения: Shamus Rezol

Можно добавить статический метод к классу MyClass, который будет преобразовывать YourClass в MyClass. Правда, в данном примере преобразований по-факту не будет.

# @name 66b260a0cf9845989b9d21c897fe9b1a.py

class MyClass:
    def A(self):
        print(1)

    @staticmethod
    def CastFromYourClass(src):
        '''Преобразует YourClass в MyClass.

        Параметр src Экземпляр класса YourClass.

        Возвращает экземпляр класса MyClass.
        '''
        if not isinstance(src, YourClass):
            raise TypeError("Параметр src не YourClass.")
        instance = MyClass()
        # Здесь различные преобразования.
        # Например, instance.data = src.data.lower()
        return instance

class YourClass(MyClass):
    def A(self):
        print(2)

src = YourClass()
instance = MyClass.CastFromYourClass(src) # Преобразуем YourClass в MyClass.
instance.A()
print(type(instance)) # instance - MyClass

Можно это же сделать в инициализаторе класса MyClass, но придется заморачиваться с перегрузкой параметров инициализатора.

Если хотите также, как и у вас, то вот еще один вариант:

class MyClass:
    def A(self):
        print(1)

class YourClass(MyClass):
    def __new__(_cls):
        return object.__new__(MyClass)

    def A(self):
        print(2)

your_class = YourClass()
your_class.A() # 1

Вот только экземпляры класса YourClass теперь невозможно будет получить адекватным способом, и это даже не преобразование из одного экземпляра в другой.

→ Ссылка
Автор решения: Andy Pavlov

Можно сделать monkey patching такого вида, переназначив метод через __setattr__ внутри объекта, к примеру.

class MyClass:
    def A(self):
        print(1)

class YourClass(MyClass):
    def A(self):
        print(2)

your_class = YourClass()
# Вариант 1
your_class.__setattr__('A', MyClass().A) 
your_class.A()  # 1

# Или вариант 2
your_class.A = MyClass().A
your_class.A()  # 1
→ Ссылка