Python 类装饰器

4 投票
2 回答
2749 浏览
提问于 2025-04-16 05:49

我正在尝试装饰一个实际的类,使用了以下代码:

def my_decorator(cls):
    def wrap(*args, **kw):
        return object.__new__(cls)
    return wrap

@my_decorator
class TestClass(object):
    def __init__(self):
        print "__init__ should run if object.__new__ correctly returns an instance of cls"


test = TestClass() # shouldn't TestClass.__init__() be run here?

虽然没有错误,但我也没有看到来自 TestClass.__init__() 的消息。

根据新式类的文档

通常的实现是通过调用父类的 __new__() 方法来创建类的新实例,使用 super(currentclass, cls).__new__(cls[, ...]) 并传入适当的参数,然后在返回之前根据需要修改新创建的实例。

如果 __new__() 返回的是 cls 的一个实例,那么新实例的 __init__() 方法会被调用,像这样 __init__(self[, ...]),其中 self 是新实例,剩下的参数和传给 __new__() 的参数是一样的。

你知道为什么 __init__ 没有运行吗?

另外,我尝试像这样调用 __new__

return super(cls.__bases__[0], cls).__new__(cls)

但它会返回一个 TypeError

TypeError: super.__new__(TestClass): TestClass is not a subtype of super

2 个回答

0

我也说不清楚具体原因,但这个小技巧确实能让 __init__ 这个方法运行起来。

def my_decorator(cls):
    print "In my_decorator()"
    def wrap(*args, **kw):
        print "In wrap()"
        return cls.__init__(object.__new__(cls), *args, **kw)
    return wrap

@my_decorator
class TestClass(object):
    def __init__(self):
        print "__init__ should run if object.__new__ correctly returns an instance of cls"
10

__init__ 方法没有被执行,因为 object.__new__ 并不知道要去调用它。如果你把它改成 cls.__call__(*args, **kwargs),或者更好的是 cls(*args, **kwargs),这样就可以正常工作了。记住,类是可以被调用的:调用一个类会产生一个新的实例。单单调用 __new__ 只是返回一个实例,但并没有进行初始化。另一种方法是先调用 __new__,然后手动调用 __init__,但这其实只是替代了已经在 __call__ 中实现的逻辑。

你引用的文档是指在类的 __new__ 方法内部调用 super。而在这里,你是从外部调用它,并不是我之前讨论的那种常规方式。

撰写回答