通过重写__new__不起作用装饰类的方法?

问题描述 投票:1回答:1

我想我的装饰类的所有方法。我在这里写用于说明目的的样品小装饰。

装饰:

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()

我不确定

  1. 为什么“一)压倒一切的__new__”不工作?
  2. 为什么方法__new__的签名是在元类有什么不同?

有人可以帮助我了解我是什么在这里失踪。

python metaclass python-internals
1个回答
3
投票

你似乎__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__足以初始化实例的属性。但是,对于不可改变的类型,如inttuple,你只能使用__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()最终无所作为。

如果你想挂接到类的创建,那么你想有一个元类。

© www.soinside.com 2019 - 2024. All rights reserved.