Search code examples
pythonpython-3.xpython-decorators

Add decorator from string


I have a decorator like this:

def foo(func):
    """Will print the args and kwargs of a func"""
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print('Do I have args?')
        print(args, kwargs, sep='\n')

        return func(*args, **kwargs)

    return wrapper

And a 'decorator maker' like this:

def add_checks(*decorators):
    """Adds decorators to a func"""
    def check(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # how do I add here the `*decorators`?
            return func(*args, **kwargs)

        return wrapper

    return check

How do I add decorators by the string? So it's something like this:

@add_checks('foo')
def bar(a, b, c=1):
    return (a * b) / c

print(bar(5, 2, c=5))
>>> Do I have args?
>>> [5, 2]
>>> {'c': 5}
>>> 2

Solution

  • You just need to iterate over *decorators:

    import functools
    
    
    def foo(func):
        """Will print the args and kwargs of a func"""
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print('Do I have args?')
            print(args, kwargs, sep='\n')
            #return func(*args, **kwargs)
    
        return wrapper
    
    
    def add_checks(*decorators):
        """Adds decorators to a func"""
        def check(func):
            @functools.wraps(func)
            def wrapper(*args, **kwargs):
                for dec in decorators:
                    if isinstance(dec, str):
                        # lookup for the function in globals()
                        globals()[dec](func)(*args, **kwargs)
                    else:
                        dec(func)(*args, **kwargs)
    
                return func(*args, **kwargs)
    
            return wrapper
    
        return check
    
    
    @add_checks(foo)  # reference to the function!
    def bar(a, b, c=1):
        return (a * b) / c
    
    
    @add_checks("foo")
    def bar_strDecorated(a, b, c=1):
        return (a * b) / c
    
    
    print(bar(5, 2, c=5))
    print(bar_strDecorated(5, 2, c=5))
    

    Out:

    Do I have args?
    (5, 2)
    {'c': 5}
    2.0
    Do I have args?
    (5, 2)
    {'c': 5}
    2.0