У меня есть дочерние классы, которые наследуют некоторые базовые функции от родительского класса. Дочерние классы должны иметь универсальный конструктор prepare_and_connect_constructor()
, который совершает магию вокруг создания объекта родительского класса. Для простоты, волшебство делается простым декоратором на основе функций (в конечном счете, он должен быть частью родительского класса).
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"))
Используя этот код, я наконец получаю
obj = super().__init__(a)
TypeError: __init__() missing 1 required positional argument: 'a'
при запуске prepare_and_connect_constructor()
.
На самом деле я ожидаю, что вызов super.__init__(a)
должен быть таким же, как в Child.__init__
. Я предполагаю, что причина связана с classmethod
, но я не могу понять это.
Что не так с этим вызовом?
Обновление : В общем, что былонеправильно то, что __init__
не возвращает объект.
Из-за подсказок и мыслей из ответов я изменил свой код для достижения того, что мне нужно:
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_magic
теперь является частью класса Parent
(с использованием staticmethod), так как он связан с общей функциональностью - Каждый дочерний класс (добавлен еще один для иллюстрации) имеет свой собственный
prepare_and_connect_constructor
classmethod , который вызывает свой собственный конструктор и при необходимости выполняет дополнительную работу