Vader
Vader

Reputation: 6716

Alternative constructor with inheritance (parent and 'grandparent')

I am trying to make my alternative constructor for Foo3 work that is not supposed to need any inputs.

class Foo1:

    def __init__(self, x):
        """
        Constructor requires x
        """
        print("I am Foo1")

    @classmethod
    def from_list(cls, some_list):
        """
        Alternative constructor
        """
        return cls(2)

class Foo2(Foo1):
    pass

class Foo3(Foo2):

    def __init__(self):
        """
        Same constructor as Foo1 but x is always 5
        """
        super(Foo3, self).__init__(5)

    @classmethod
    def from_list(cls):
        """
        Alternative constructor
        Same as Foo1 from_list except some_list is always [1, 2, 3]
        """
        self = super(Foo2, Foo3).from_list(some_list=[1, 2, 3])
        return self

foo1_using_init = Foo1(2)
foo1_using_from_list = Foo1.from_list([5, 6, 7])

foo3_using_init = Foo3()
foo3_using_from_list = Foo3.from_list()  # broken

This is the output

Traceback (most recent call last):
  File "C:\Usersp.py", line 37, in <module>
    foo3_using_from_list = Foo3.from_list()  # broken
  File "C:\Usersp.py", line 30, in from_list
    self = super(Foo2, Foo3).from_list(some_list=[1, 2, 3])
  File "C:\Userp.py", line 11, in from_list
    return cls(2)
TypeError: __init__() takes 1 positional argument but 2 were given

Upvotes: 0

Views: 115

Answers (1)

Matiiss
Matiiss

Reputation: 6156

When you use

self = super().from_list(some_list=[1, 2, 3])

It ultimately ends up calling this

return cls(2)

In that case it is the same as

return Foo3(2)

But clearly the __init__ method doesn't take any additional arguments so it will raise an error.

To fix this you can just use * to get all the arguments and then just ... ignore them:

class Foo3(Foo2):
    def __init__(self, *args, **kwargs):
        """
        Same constructor as Foo1 but x is always 5
        """
        super().__init__(5)

Upvotes: 2

Related Questions