What's the correct syntax?
class Foo:
def hello(self):
print "Hello cruel world!"
def greet_first(self, f):
self.hello()
return lambda *args, **kwargs: f(*args, **kwargs)
@greet_first
def goodbye(self, concat):
print "Goodbye {0}".format(concat)
if __name__=='__main__':
bar = Foo()
bar.goodbye(' and thanks for all the fish')
Traceback (most recent call last):
File "prog.py", line 1, in <module>
class Foo:
File "prog.py", line 9, in Foo
@greet_first
TypeError: greet_first() takes exactly 2 arguments (1 given)
A decorator is called immediately, it is not treated as a method of Foo
but rather is seen as a local function instead. The @greet_first
syntax effectively means:
goodbye = greet_first(goodbye)
and is executed immediately. It is not a bound method, so the self
parameter is not included. There is no point in making greet_first
a method. Move it out and remove the self
argument altogether.
You need to adjust your decorator to return a callable to replace goodbye
:
def greet_first(f):
def wrapper(self, *args, **kwargs):
self.hello()
return f(self, *args, **kwargs)
return wrapper
so that self.hello()
is called every time goodbye
is called.
If you have to make greet_first
part of Foo
, you can use a @staticmethod
decorator but you have to jump through an extra hoop just to be able to use it for other method declarations; you have to treat it as the descriptor it has become and call .__get__()
on it:
class Foo(object):
def hello(self):
print "Hello cruel world!"
@staticmethod
def greet_first(f):
def wrapper(self, *args, **kwargs):
self.hello()
return f(self, *args, **kwargs)
return wrapper
@greet_first.__get__(object)
def goodbye(self, concat):
print "Goodbye {0}".format(concat)
I call .__get__()
with an arbitrary type (object
in this case) because staticmethod
ignores that argument anyway; we can't use Foo
here because that class has not yet been finalized while inside the code that is part of it's definition.
Note that for @staticmethod
to work at all you need to inherit from object
in Python 2.