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
                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


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):
            output = original_func(*args, **kwargs)
            return output
        return wrappee



Related links


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 powered by Disqus