Search code examples
pythonpython-3.xinheritanceconstructorsuper

Init super with existing instance?


Suppose I have:

class Super:
  def __init__(self,a):
     self.a = a
  @classmethod
  def from_b(cls,b):
     return cls(b.to_a())

class Regular(Super):
   def __init__(self,b):
      # how to set my super to the output of
      super = super.from_b(b)

How do I correctly initialize the super class with the output of the super class method rather than init?

My OOP background is in C++ and I am continually getting into these scenarios due to the ability to overload constructors in C++, so a workaround for this would be awesome.


Solution

  • @shx2's answer works but wastefully/awkwardly creates a throw-away Super object just to initialize the new Regular object with its a attribute.

    If you have control over the source of Super, you can make the from_b method create an instance of the given subclass, and have the subclass call the from_b method in its __new__ method instead, so that a Regular object can be both created and initialized directly:

    class Super:
        def __init__(self, a):
            self.a = a
    
        @classmethod
        def from_b(cls, b):
            obj = super().__new__(cls)
            cls.__init__(obj, b.to_a())
            return obj
    
    class Regular(Super):
        def __new__(cls, b):
            return super().from_b(b)
    

    so that the following assertions will pass:

    from unittest.mock import Mock
    
    obj = Regular(Mock())
    assert type(obj) is Regular
    assert obj.a.to_a.is_called()