I have child classes which inherit some basic functionality from a parent class. The child classes shall have a generic constructor prepare_and_connect_constructor() which does some magic around the object creation of the parent class. For simplicity, the magic is done by a simple function based decorator (ultimately, it should be a part of the parent class).
def decorate_with_some_magic(func): def prepare_and_connect(*args, **kwargs): print("prepare something") print("create an object") obj = func(*args, **kwargs) print("connect obj to something") return obj return prepare_and_connect class Parent: def __init__(self, a): self.a = a def __repr__(self): return f"{self.a}" class Child(Parent): @classmethod @decorate_with_some_magic def prepare_and_connect_constructor(cls, a, b): """ use the generic connection decorator right on object creation """ obj = super().__init__(a) # put some more specific attributes (over the parents class) obj.b = b return obj def __init__(self, a, b): """ init without connecting """ super().__init__(a) self.b = b def __repr__(self): return f"{self.a}, {self.b}" if __name__ == '__main__': print(Child.prepare_and_connect_constructor("special child", "needs some help")) Using this code i finally get
obj = super().__init__(a) TypeError: __init__() missing 1 required positional argument: 'a' when running prepare_and_connect_constructor().
Actually I would expect that the super.__init__(a) call should be the same as in Child.__init__. I guess the reason is related to the classmethod but I can't figure it out.
What's wrong with this call?
Update: In general what was wrong is that __init__ doesn't return an object.
Due to the hints and thoughts from the answers i modified my code to achieve what i need:
class Parent: def __init__(self, a): self.a = a @staticmethod def decorate_with_some_magic(func): def prepare_and_connect(*args, **kwargs): print("prepare something") print("create an object") obj = func(*args, **kwargs) print("connect obj to something") return obj return prepare_and_connect def __repr__(self): return f"{self.a}" class ChildWithOneName(Parent): @classmethod @Parent.decorate_with_some_magic def prepare_and_connect_constructor(cls, a, b): """ use the generic connection decorator right on object creation """ obj = super().__new__(cls) obj.__init__(a, b) print("Does the same as in it's __init__ method") return obj def __init__(self, a, b): """ init without connecting """ super().__init__(a) self.b = b def __repr__(self): return f"{self.a}, {self.b}" class GodChild(Parent): @classmethod @Parent.decorate_with_some_magic def prepare_and_connect_constructor(cls, a, names): """ use the generic connection decorator right on object creation """ obj = super().__new__(cls) obj.__init__(a, names) # perform some more specific operations obj.register_all_names(names) print("And does some more stuff than in it's __init__ method") return obj def __init__(self, a, already_verified_names): """ init without connecting """ super().__init__(a) self.verified_names = already_verified_names def register_all_names(self, names=[]): self.verified_names = [] def verify(text): return True for name in names: if verify(name): self.verified_names.append(name) def __repr__(self): return f"{self.a}, {self.verified_names}" if __name__ == '__main__': print(ChildWithOneName.prepare_and_connect_constructor("special child", "needs some help"), end='\n\n') print(GodChild.prepare_and_connect_constructor("unknown child", "needs some verification"), end='\n\n') print(ChildWithOneName("my child", "is clean and doesn't need extra magic")) decorate_with_some_magicis now a part of theParentclass (using a staticmethod) as it is a related generic functionality- Each child class (added one more for illustration) has it's own
prepare_and_connect_constructorclassmethod, which calls its own constructor and does optionally some additional work
__init__doesn't return anything, and since you are callingsuperfrom a class method,super().__init__requires an explicit instance as its first argument.