Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I extend a library's decorator?

I would like to extend a library's decorator. I know that I can just call both decorators:

@my_decorator
@lib_decorator
def func():
    pass

But I would like to avoid having to pass @lib_decorator to each function each time. I would like my decorator to automatically decorate func() with lib_decorator. How can I do this? Can they be nested?

like image 633
drs Avatar asked Dec 23 '15 20:12

drs


People also ask

How do you extend a decorator in Python?

Simply write the decorator name using the “@” symbol before the function definition as shown below. In the following script, the functionality of the my_func() function is extended using the my_decorator() function. Finally, you can also extend multiple functions using a single decorator.

How do you call a decorator in Python?

The call() decorator is used in place of the helper functions. In python, or in any other languages, we use helper functions for three major motives: To identify the purpose of the method. The helper function is removed as soon as its job is completed.

What is a function decorator?

By definition, a decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it. This sounds confusing, but it's really not, especially after you've seen a few examples of how decorators work. You can find all the examples from this article here.


2 Answers

You can incorporate the lib's decorator within yours. For simple, argument-less decorators, it's rather straight-forward:

def my_decorator():
    @lib_decorator  # <--- Just include the lib's decorator here
    def inner:
        func(*args, **kwargs)
    return inner

It's a bit trickier for decorators that have arguments. Just remember that your decorator is replacing the decorated function with the inner-most function. So that's the one you need to decorate. So if you call your decorator with args, e.g.

@my_decorator(arg)
def func():
    pass

Then decorate the inner function with the lib decorator:

def my_decorator(arg):
    def wrapper(func):

        @lib_decorator  # <--- Just include the lib's decorator here
        def inner(*args, **kwargs):
            func(*args, **kwargs)

        return inner

    return wrapper

Or, using the class form of the decorator function:

class my_decorator():
    def __init__(self, arg):
        pass

    def __call__(self, func):
        @lib_decorator  # <--- Just include the lib's decorator here
        def inner(*args, **kwargs):
            func(*args, **kwargs)

        return inner
like image 92
drs Avatar answered Oct 23 '22 18:10

drs


You can easily transform a decoration like yours:

@my_decorator
@lib_decorator
def func():
    pass

To this simpler decoration, using function composition:

my_composed_decorator = lambda func: my_decorator(lib_decorator(func))

@my_composed_decorator
def func():
    pass
like image 24
shx2 Avatar answered Oct 23 '22 17:10

shx2