Search code examples
pythonsuper

Python : Convert Superclass instance to Subclass


I am given an object a of the class A. I do not understand how class A works. Furthermore an unknown number of methods throughout the module I am using use A. So for all practical purposes A is unknown and we can only manipulate an instance of it and one known method, method2.

I am given an instance a. I want to convert a to a class B such that it remains identical in every respect except that method2 (which was present in the original class A and prints a) now prints b. How do I modify the piece of code below to be able to do that ?

class B(A):
    def __init__(self,**kwargs):
        super().__init__(**kwargs)

    def method2(self):
        print('b')

a.method1() #prints '1'
a.method2() #prints 'a'
print(a[0]) #prints 1
#a = convertAtoB(a)
a.method1() #prints '1'
a.method2() #should print 'b'
print(a[0]) #prints 1

I am aware of a previous answer to a similar question which involved using __getattr__ however when trying the below piece of code:

class B(object):
    def __init__(self, a):
        self.__a = a

    def __getattr__(self, attr):
        return getattr(self.__a, attr)

    def __setattr__(self, attr, val):
        object.__setattr__(self, attr, val)
    
    def method2(self):
        print('b')

I got, in the practical problem I am having, the error TypeError: 'B' object is not subscriptable.

edit : added a subscript test, as I mentioned above, I don't entirely understand how A works or which methods in the imported module need A to work.


Solution

  • You can reassign object's __class__ to a new type. I've put comment inside the code: (take care of object initialization yourself if necessary)

    class A:
        def func_A_1(self):
            return 'func_A_1 is running'
    
        def func_A_2(self):
            return 'func_A_2 is running'
    
        def method2(self):
            return 'method2 of class A'
    
    
    class B(A):
        def method2(self):
            return 'method2 of class B'
    
    
    obj = A()
    
    print(obj)
    print(obj.func_A_1())
    print(obj.method2())
    print('------------------------------')
    
    # turning object of A to B
    obj.__class__ = B
    print(obj)
    
    # still have access to A's methods
    print(obj.func_A_1())
    
    # This method is now for B
    print(obj.method2())
    

    output :

    <__main__.A object at 0x0000012FECFACFD0>
    func_A_1 is running
    method2 of class A
    ------------------------------
    <__main__.B object at 0x0000012FECFACFD0>
    func_A_1 is running
    method2 of class B