Search code examples
pythonargumentsdecorator

Python class decorator arguments


I'm trying to pass optional arguments to my class decorator in python. Below the code I currently have:

class Cache(object):
    def __init__(self, function, max_hits=10, timeout=5):
        self.function = function
        self.max_hits = max_hits
        self.timeout = timeout
        self.cache = {}

    def __call__(self, *args):
        # Here the code returning the correct thing.


@Cache
def double(x):
    return x * 2

@Cache(max_hits=100, timeout=50)
def double(x):
    return x * 2

The second decorator with arguments to overwrite the default one (max_hits=10, timeout=5 in my __init__ function), is not working and I got the exception TypeError: __init__() takes at least 2 arguments (3 given). I tried many solutions and read articles about it, but here I still can't make it work.

Any idea to resolve this? Thanks!


Solution

  • @Cache(max_hits=100, timeout=50) calls __init__(max_hits=100, timeout=50), so you aren't satisfying the function argument.

    You could implement your decorator via a wrapper method that detected whether a function was present. If it finds a function, it can return the Cache object. Otherwise, it can return a wrapper function that will be used as the decorator.

    class _Cache(object):
        def __init__(self, function, max_hits=10, timeout=5):
            self.function = function
            self.max_hits = max_hits
            self.timeout = timeout
            self.cache = {}
    
        def __call__(self, *args):
            # Here the code returning the correct thing.
    
    # wrap _Cache to allow for deferred calling
    def Cache(function=None, max_hits=10, timeout=5):
        if function:
            return _Cache(function)
        else:
            def wrapper(function):
                return _Cache(function, max_hits, timeout)
    
            return wrapper
    
    @Cache
    def double(x):
        return x * 2
    
    @Cache(max_hits=100, timeout=50)
    def double(x):
        return x * 2