我想我的装饰类的所有方法。我在这里写用于说明目的的样品小装饰。
装饰:
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诠释班里的第一名,但我想了解这样做的另外两个不同的方法。
一)重写__new__
class Spam:
def __new__(cls, *args, **kwargs):
clsobj = super().__new__(cls)
clsobj = debugmethods(clsobj)
return clsobj
def __init__(self):
pass
def foo(self):
pass
def bar(self):
pass
spam = Spam()
spam.foo()
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__
的签名是在元类有什么不同?有人可以帮助我了解我是什么在这里失踪。
你似乎__new__
和元类之间相混淆。 __new__
被调用来创建一个新的对象(从一个类的实例中,从元类的类),它不是一个钩“创建的类”。
正常模式是:
Foo(...)
被翻译成type(Foo).__call__(Foo, ...)
,看到special method lookups为这是为什么。一类的type()
是它的元类。type.__call__
实现时Foo
是一个自定义的Python类将调用__new__
创建一个新的实例,然后调用该实例上__init__
方法如果结果确实是Foo
类的实例:
def __call__(cls, *args, **kwargs): # Foo(...) -> cls=Foo
instance = cls.__new__(cls, *args, **kwargs) # so Foo.__new__(Foo, ...)
if isinstance(instance, cls):
instance.__init__(*args, **kwargs) # Foo.__init__(instance, ...)
return instance
因此,在创建Foo.__new__
类本身时,只有创建Foo
的实例时Foo
不叫。您通常不需要在类中使用__new__
,因为__init__
足以初始化实例的属性。但是,对于不可改变的类型,如int
或tuple
,你只能使用__new__
准备新实例的状态,因为它一旦建立,你不能改变一个不可改变的对象的属性。 __new__
也是有帮助的,当你想改变什么样的情况下ClassObj()
农产品(如创建单身或生产专用子类来代替)。
同样__call__
- > __new__
也许__init__
过程适用于元类。类的名称,该类基地,类主体,作为字典通常是:一个class Foo: ...
声明是通过调用元类来创建一个类的对象,在经过3个参数来实现。随着class Spam(metaclass = debugmeta): ...
,这意味着debugmeta('Spam', (), {...})
被调用,这意味着debugmeta.__new__(debugmeta, 'Spam', (), {...})
被调用。
你的第一次尝试,设置Spam.__new__
不起作用,因为你没有创建一个类的对象那里。相反,super().__new__(cls)
创建一个没有属性的空Spam()
实例,因此vars()
返回一个空字典和debugmethods()
最终无所作为。
如果你想挂接到类的创建,那么你想有一个元类。