Note:
The accepted answer on the other question shows how to use the parent decorater.
The accepted answer on this question shows moving the decorator to the module scope.
EDIT: Using the previous example was a bad idea. Hopefully this is more clear:
class A:
def deco( func ):
print repr(func)
def wrapper( self, *args ):
val = func( *args )
self.do_something()
return val
return wrapper
def do_something( self ):
# Do something
print 'A: Doing something generic for decoration'
@deco
def do_some_A_thing ( self ):
# Do something
print 'A: Doing something generic'
class B ( A ):
@deco
def do_some_B_thing( self ):
# Do something
print "B: Doing something specific"
a = A()
b = B()
a.do_some_A_thing()
b.do_some_B_thing()
#Expected Output:
#A: Doing something generic
#A: Doing something generic for decoration
#B: Doing something specific
#A: Doing something generic for decoration
This code generates a NameError: name ‘deco’ is not defined inside B.
The decorator needs to be inside the class scope because I require access to stored state.
Third Edit: On Sven’s suggestions, I tried this:
class A:
def deco( func ):
def wrapper( self, *args ):
val = func( *args )
self.do_something(*args)
return val
return wrapper
def do_something( self ):
# Do something
print 'A: Doing something generic for decoration'
@deco
def do_some_A_thing ( self ):
# Do something
print 'A: Doing something generic'
deco = staticmethod(deco)
class B ( A ):
@A.deco
def do_some_B_thing( self ):
# Do something
print "B: Doing something specific"
a = A()
b = B()
a.do_some_A_thing()
b.do_some_B_thing()
#Expected Output:
#A: Doing something generic
#A: Doing something generic for decoration
#B: Doing something specific
#A: Doing something generic for decoration
I now have have TypeError: do_some_A_thing() takes exactly 1 argument (0 given). Any pointers?
The problem is that inheritance works for instance attribute lookup, not for class definitions. So when you try to decorate with A.deco in B, it can’t find it. The solution is to move
decoout to module scope, and because there is nothing magic about the nameself, you can keep using it. You also need to explicitly passselftofunc, and you do not need to pass it inself.do_something(). Here’s the updated code: