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 deco
out to module scope, and because there is nothing magic about the name self
, you can keep using it. You also need to explicitly pass self
to func
, and you do not need to pass it in self.do_something()
. Here's the updated code:
def deco( func ):
print repr( func )
def wrapper( self, *args ):
val = func( self, *args )
self.do_something()
return val
return wrapper
class A:
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()
Answer to edited question: Your question has become an exact duplicate of the question it linked to before the edit. An easier fix than the one given in the answers to the linked question is to simply move the decorator out of the class namespace.
Moreover, self.do_something(self)
should be self.do_something()
instead -- don't pass self
twice.
Answer to question before the edit: If you only ever want to decorate instance methods with your decorator, don't collapse the self
parameter into *args
, but rather leave it explicit:
def _deco(func):
def wrapper(self, *args):
res = func(self, *args)
self.some_other_baseclass_method(*args)
return res
return wrapper
That said, I don't see the point of having _deco
inside the class namespace and turning it into a staticmethod
. Just move it to the module namespace.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With