Reputation:
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 usingsuper(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
Upvotes: 4
Views: 2759
Reputation: 1488
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"
Upvotes: 0
Reputation: 70994
__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.
Upvotes: 10