简体   繁体   中英

Python Class Decorator

I am trying to decorate an actual class, using this code:

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?

I get no errors, but I also don't see the message from TestClass.__init__() .

According to the docs for new-style classes :

Typical implementations create a new instance of the class by invoking the superclass's __new__() method using super(currentclass, cls).__new__(cls[, ...]) with appropriate arguments and then modifying the newly-created instance as necessary before returning it.

If __new__() returns an instance of cls, then the new instance's __init__() method will be invoked like __init__(self[, ...]) , where self is the new instance and the remaining arguments are the same as were passed to __new__() .

Any ideas why __init__ isn't running?

Also, I have tried to call __new__ like this:

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

but it would return a TypeError :

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

__init__ isn't running because object.__new__ doesn't know to call it. If you change it to cls.__call__(*args, **kwargs) , or better, cls(*args, **kwargs) , it should work. Remember that a class is a callable: calling it produces a new instance. Just calling __new__ returns an instance but doesn't go through the initialization. An alternative would be to call __new__ and then manually call __init__ but this is just replacing the logic that is already embodied in __call__ .

The documentation that you quote is referring to calling super from within the __new__ method of the class. Here, you are calling it from the outside and not in the usual way as I've already discussed.

Couldn't tell you the reason but this hack does run __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"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM