Python 类方法上的装饰器
我的子类继承了父类的一些基本功能。 子类应该有一个泛型构造函数Python 类方法上的装饰器,python,decorator,class-method,Python,Decorator,Class Method,我的子类继承了父类的一些基本功能。 子类应该有一个泛型构造函数prepare\u和\u connect\u constructor(),它在父类的对象创建过程中发挥了一些魔力。 为了简单起见,这个魔术是由一个简单的基于函数的装饰器完成的(最终,它应该是父类的一部分) 使用这段代码,我终于得到了 obj=super() TypeError:\uuuu init\uuuu()缺少1个必需的位置参数:“a” 运行时,准备和连接构造函数() 实际上,我希望super.\uuuu init\uuuu(a
prepare\u和\u connect\u constructor()
,它在父类的对象创建过程中发挥了一些魔力。
为了简单起见,这个魔术是由一个简单的基于函数的装饰器完成的(最终,它应该是父类的一部分)
使用这段代码,我终于得到了
obj=super()
TypeError:\uuuu init\uuuu()缺少1个必需的位置参数:“a”
运行时,准备和连接构造函数()
实际上,我希望super.\uuuu init\uuuu(a)
调用应该与Child.\uuuu init\uuuu
中的调用相同。
我想原因与classmethod
有关,但我想不出来
这个电话怎么了
更新:通常错误在于\uuuu init\uuuu
不返回对象
由于答案中的提示和想法,我修改了代码以实现所需:
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"))
decoration\u with\u some\u magic
现在是Parent
类的一部分(使用staticmethod),因为它是相关的通用功能
- 每个子类(添加一个用于说明)都有自己的
prepare\u和
classmethod,它调用自己的构造函数并可选地执行一些附加工作
您对神奇的方法\uuuuu init\uuuuuuu
和\uuuu new\uuuuuuuu
有一点误解<代码>\uuuu new\uuuu
创建新对象,例如返回类的实例<代码>\uuuu init\uuuu只是在适当的位置修改对象。因此,解决您的问题的简单方法是:
@classmethod
@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)
# put some more specific attributes (over the parents class)
obj.b = b
return obj
然而,我认为你不应该这样使用它。相反,您可能应该覆盖
\uuuu new\uuu
装饰程序在可调用项上的工作。因为调用函数和初始化类之间没有区别,所以可以直接在类上使用decorator:
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:
@classmethod
def prepare_and_connect_constructor(cls, a, b):
return decorate_with_some_magic(cls)(a, b)
def __init__(self, a):
self.a = a
def __repr__(self):
return f"{self.a}"
class Child(Parent):
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__':
normal_child = Child("normal child", "no help needed")
print(normal_child)
special_child = Child.prepare_and_connect_constructor("special child", "needs some help")
print(special_child)
输出:
normal child, no help needed
prepare something
create an object
connect obj to something
special child, needs some help
\uuuuu init\uuuu
不返回任何内容,而且由于您是从类方法调用super
,super()。\uuuuuuu init\uuuuu
需要一个显式实例作为其第一个参数。是的,我没有考虑过这一点。要正确执行此操作,\uuuu new\uuuuu
的更改应该是什么?@maggie,这会假设您始终想要连接。是这样吗?不是,这就是我为什么要问的原因。它应该是另一种选择(编写更少的代码)。但情况并非总是如此,但我想要一个“普通”构造函数和一个替代构造函数。用这种方法是不可能的。在课堂之外使用装饰器。请看我修改后的答案。好的,这很有效,看起来也不错,但是对于多个子类,这些类的工作方式是不同的。它不能保证在正常构造函数中发生相同的事情。。。也许这不是我想到的最好的设计,但是用类方法做不可能吗?现在用类方法。
normal child, no help needed
prepare something
create an object
connect obj to something
special child, needs some help