How do I initialize the parent class using a class method instead of calling the constructor?

Viewed 84

I have class A which I want to inherit from, this class has a class method that can initialize a new instance from some data. I don't have access to the code for from_data and can't change the implementation of A.

I want to initialize new instances of class B using the same data I would pass to the A's from_data method. In the solution I came up with I create a new instance of A in __new__(...) and change the __class__ to B. __init__(...) can then further initialize the "new instance of B" as normal. It seems to work but I'm not sure this will have some sort of side effects.

So will this work reliably? Is there a proper way of achieving this?

class A:
    def __init__(self, alpha, beta):
        self.alpha = alpha
        self.beta = beta

    @classmethod
    def from_data(cls, data):
        obj = cls(*data)
        return obj


class B(A):
    def __new__(cls, data):
        a = A.from_data(data)
        a.__class__ = cls
        return a

    def __init__(self, data):
        pass


b = B((5, 3))
print(b.alpha, b.beta)
print(type(b))
print(isinstance(b, B))

Output:

5 3
<class '__main__.B'>
True
1 Answers

It could be that your use-case is more abstract than I am understanding, but testing out in a REPL, it seems that calling the parent class A constructor via super()

class A:
    # ...


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


b = B((5, 3))
print(b.alpha, b.beta)
print(type(b))
print(isinstance(b, B))

also results in

5 3
<class '__main__.B'>
True

Is there a reason you don't want to call super() to instantiate a new instance of your child class?


Edit:

So, in case you need to use the from_data constructor... you could do something like

#... class A

class B(A):
    def __init__(self, data):
        a_obj = A.from_data(data)
        for attr in a_obj.__dict__:
            setattr(self, attr, getattr(a_obj, attr))

That is really hacky though... and not guaranteed to work for all attrs of A class object, especially if the __dict__ function has been overloaded.

Related