我想装饰我班上所有的方法。我在这里写了一个小装饰的例子,以供说明。在
装饰工:
def debug(func):
msg = func.__name__
@wraps(func)
def wrapper(*args, **kwargs):
print(msg)
return func(*args, **kwargs)
return wrapper
def debugmethods(cls):
for key, val in vars(cls).items():
if callable(val):
setattr(cls, key, debug(val))
return cls
现在我要装饰我班的所有方法。一种简单的方法是在类的顶部使用@debugmethods注释,但是我正在尝试理解另外两种不同的方法。在
a)重写__new__
b)编写元类
class debugmeta(type):
def __new__(cls, clsname, bases, clsdict):
clsobj = super().__new__(cls, clsname, bases, clsdict)
clsobj = debugmethods(clsobj)
return clsobj
class Spam(metaclass = debugmeta):
def foo(self):
pass
def bar(self):
pass
spam = Spam()
spam.foo()
我不确定
__new__
”不起作用?在有人能帮我理解我在这里遗漏了什么吗。在
您似乎混淆了}来创建一个新对象(类中的实例,元类中的类),它不是“类创建”钩子。在
__new__
和元类。^调用{正常模式是:
Foo(...)
被转换为type(Foo).__call__(Foo, ...)
,请参见{a1}了解原因。类的type()
是它的元类。在当
Foo
是自定义Python类时使用的标准type.__call__
实现将调用__new__
来创建一个新实例,如果结果确实是Foo
类的实例,则在该实例上调用__init__
方法:因此,只有在创建
Foo
的实例时,Foo.__new__
不会被调用。通常不需要在类中使用
__new__
,因为__init__
足以初始化实例的属性。但是对于不可变的类型,比如int
或tuple
,您只能使用__new__
来准备新的实例状态,因为一旦不可变对象被创建,就不能更改它的属性。__new__
在您希望更改ClassObj()
生成的实例类型时也很有用(例如创建单例实例或生成专门的子类)。在相同的}过程也适用于元类。一个}。在
__call__
->;__new__
和{class Foo: ...
语句是通过调用元类来创建类对象来实现的,传递3个参数:类名、类基和类主体,通常作为字典。对于class Spam(metaclass = debugmeta): ...
,这意味着调用debugmeta('Spam', (), {...})
,这意味着调用{您的第一次尝试设置
Spam.__new__
不起作用,因为您没有在那里创建类对象。相反,super().__new__(cls)
创建了一个没有属性的空Spam()
实例,因此vars()
返回一个空字典,debugmethods()
最终什么也不做。在如果你想钩住类的创建,那么你需要一个元类。在
相关问题 更多 >
编程相关推荐