Sure it's possible. All the @decorator
syntax does is define the function that follows, then call the decorator, passing in the function that followed and replacing the reference to that function with whatever was returned.
So the following:
@foo
def bar():
pass
is translated to:
def bar():
pass
bar = foo(bar)
This means that your t.Test_method_2()
method must expect one argument, the to-be-decorated function, and return something callable:
import functools
def Test_method_2(self, func):
@functools.wraps(func)
def wrapper(self, *args, **kw):
print 'Wrapped function name:', func.__name__
return func(*args, **kw)
return wrapper
would be the minimal decorator that returns a wrapper function, and prints the name of the wrapped function when called. It doesn't matter what the argument is called; I used func
here but it can be any legal python identifier.
The self
is the standard part of the method signature. Because you are referencing Test_method_2
on an instance t
, Python automatically takes care of the self
parameter for you as it does with all methods.
Anything after @
is just an expression. So if you use the syntax:
@t.Test_method_2(a, b, c, d, e=f, g=h)
then Test_method_2()
should instead return a decorator function. One extra level of scope nesting should do that:
def Test_method_2(self, *args, **kw):
def decorator(func):
@functools.wraps(func)
def wrapper(*wrapperargs, **wrapperkw):
fargs = args + wrapperargs
fkw = dict(kw)
fkw.update(wrapperkw)
return func(*fargs, **fkw)
return wrapper
return decorator
Deconstructing this:
@t.Test_method_2(5, 6, 7, 8, baz='spam', ham='eggs')
def simple_function(x, y, z, n=m):
print 'this is a simple_function'
The part after the @
, t.Test_method_2(5, 6, 7, 8, baz='spam', ham='eggs')
returns the nested function decorator
:
@decorator
def simple_function(x, y, z, n=m):
print 'this is a simple_function'
which python then turns into:
simple_function = decorator(simple_function)
and decorator(func)
returns wrapper(*wrapperargs, **wrapperkw)
.
Calling simple_function(1, 2, foo='bar')
then results in a call to wrapper(1, 2, foo='bar')
which calls the original simple_function()
with fargs = [5, 6, 7, 8, 1, 2]
and fkw = {'baz': 'spam', 'ham': 'eggs', 'foo': 'bar'}
passed in as positional and keyword arguments.
The class decorator pattern you see in the linked questions works in a similar way; the expression after the @
returns something that is called; instead of a nested function a class instance is being created instead. It's just two different approaches to storing state for the decorator to use.
The nested functions is a little more compact to write, while using a class gives you more introspection options than a nested scope.