Python Decorators have the ability to be parameterized.
The main reason is to have more ability to change some behaviour of function/class in a more elegant DRY way.
To The Point
You can create your own decorator that will be a class.
This time we will use that, to make our code a bit more simplier and readable.
This example is a more/less based on this stackoverflow answer:
class BeforeAfterDecorator(object):
def __init__(self, before_func, after_func, which_return = 0):
self.before_func = before_func
self.after_func = after_func
self.which_return = which_return
def __call__(self, original_func):
def wrappee( *args, **kwargs):
output_before = self.before_func()
output = original_func(*args, **kwargs)
output_after = self.after_func()
if self.which_return == 1:
return output_before
elif self.which_return == 2:
return output_after
else:
return output
return wrappee
def before_function():
print("this is a more complex function that will be invoked before function")
return "before"
def after_function():
print("this is a more complex function that will be invoked after function")
return "after"
@BeforeAfterDecorator(before_function, after_function, 1)
def make_all_return_before(a,b,c):
print( 'in bar',a,b,c )
return "method"
@BeforeAfterDecorator(before_function, after_function, 2)
def make_all_return_after(a,b,c):
print( 'in bar',a,b,c )
return "method"
@BeforeAfterDecorator(before_function, after_function)
def make_all_return_output(a,b,c):
print( 'in bar',a,b,c )
return "method"
first_output = make_all_return_before('x','y','z')
print("function ended with return: ", first_output)
second_output = make_all_return_output('x','y','z')
print("function ended with return: ", second_output)
third_output = make_all_return_after('x','y','z')
print("function ended with return: ", third_output)
As you can see in script above, this decorator (BeforeAfterDecorator
) has ability to take other functions that will be invoked before decorated function and after.
Also it has third parameter that decides which output will be taken.
Where you could use that?
For example at the Fabric which can be used for deployment process. Check out my posts about using fabric.
At the stackoverflow answer you can find alternative solution to make meta-decorator that uses triple-nest function. I suggest you to check it.
This decorator looks like this:
def parametrized(dec):
def layer(*args, **kwargs):
def repl(f):
return dec(f, *args, **kwargs)
return repl
return layer
Snippets
class ParameterizedDecorator(object):
def __init__(self, your_decorator_parameter):
self.your_decorator_parameter = your_decorator_parameter
def __call__(self, original_func):
def wrappee( *args, **kwargs):
print(self.your_decorator_parameter)
output = original_func(*args, **kwargs)
return output
return wrappee
Acknowledgements
Autopromotion
Related links
- StackOverFlow - python - Decorators with Parameters?
- Decorators I: Introduction to python decorators
Thanks!
That's it :) Comment, share or don't :)
If you have any suggestions what I should blog about in the next articles - please give me a hint :)
See you in the next episode! Cheers!
Comments
comments powered by Disqus