How to control decorator on python derived class?

I would like to use a decorator to do something with a derived class (e.g. register a class or something else). Here is my code:

from functools import wraps class Basic(object): def __init__(self): print "Basic::init" def myDeco(name): # define the decorator function that acts on the actual class definition def __decorator(myclass): # do something here with the information print name, myclass # do the wrapping of the class @wraps(myclass) def __wrapper(*args, **kwargs): return myclass( *args, **kwargs) # return the actual wrapper here return __wrapper # return the decorator to act on the class definition return __decorator @myDeco("test") class Derived(Basic): def __init__(self): super(Derived, self).__init__() print "Derived::init" instance = Derived() 

which gives the following error:

 TypeError: must be type, not function 

when the super method in Derived called. I assume the Derived variable is no longer a type , but actually a __decorator function.

How can I change the decorator (and ONLY the decorator) to fix this problem?

+4
source share
2 answers

You replace the decorated class with a function, and therefore the class definition is not performed.

In particular, super(Derived, self).__init__() now goes into the super() function:

 >>> super(Derived, object()) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: must be type, not function >>> type(Derived) <type 'function'> 

Class decorators typically modify the class, add, delete, or modify its attributes, and then return the class object again.

You should not replace Derived new class, because your Derived.__init__() refers to itself by name. Replacing this name with another class will lead to pain (for example, to infinite recursion).

An example class decorator that works:

 def my_deco(name): # define the decorator function that acts on the actual class definition def decorator(cls): # do something here with the information print name, cls setattr(class, name, 'Hello world!') # return the original, augmented class return cls # return the decorator to act on the class definition return decorator 
+3
source

There were two errors in your program:

 from functools import wraps class Basic(object): def __init__(self): print "Basic::init" def myDeco(name): # define the decorator function that acts on the actual class definition def __decorator(myclass): # do something here with the information print name, myclass # do the wrapping of the class class Wrap(myclass): # error 1 realSuper = myclass # I dislike this. has anyone an other aproach def __new__(*args, **kwargs): return myclass.__new__(*args, **kwargs) # return the actual wrapper here return Wrap # return the decorator to act on the class definition return __decorator @myDeco("test") class Derived(Basic): def __init__(self): super(Derived.realSuper, self).__init__() # error 2 print "Derived::init" instance = Derived() 

Now this gives the following result:

 test <class '__main__.Derived'> Basic::init Derived::init 

First you need a class, as others have pointed out.

The second super(Derived, self).__init__() called infinite recursion:

 Traceback (most recent call last): File "<pyshell#8>", line 1, in <module> exec s File "<string>", line 32, in <module> File "<string>", line 28, in __init__ File "<string>", line 28, in __init__ File "<string>", line 28, in __init__ File "<string>", line 28, in __init__ 

For the reasons given below.

0
source

All Articles