Python class decorator arguments

前端 未结 4 1698
走了就别回头了
走了就别回头了 2020-12-24 14:50

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         


        
4条回答
  •  爱一瞬间的悲伤
    2020-12-24 15:28

    I've learned a lot from this question, thanks all. Isn't the answer just to put empty brackets on the first @Cache? Then you can move the function parameter to __call__.

    class Cache(object):
        def __init__(self, max_hits=10, timeout=5):
            self.max_hits = max_hits
            self.timeout = timeout
            self.cache = {}
    
        def __call__(self, function, *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
    

    Although I think this approach is simpler and more concise:

    def cache(max_hits=10, timeout=5):
        def caching_decorator(fn):
            def decorated_fn(*args ,**kwargs):
                # Here the code returning the correct thing.
            return decorated_fn
        return decorator
    

    If you forget the parentheses when using the decorator, unfortunately you still don't get an error until runtime, as the outer decorator parameters are passed the function you're trying to decorate. Then at runtime the inner decorator complains:

    TypeError: caching_decorator() takes exactly 1 argument (0 given).

    However you can catch this, if you know your decorator's parameters are never going to be a callable:

    def cache(max_hits=10, timeout=5):
        assert not callable(max_hits), "@cache passed a callable - did you forget to parenthesize?"
        def caching_decorator(fn):
            def decorated_fn(*args ,**kwargs):
                # Here the code returning the correct thing.
            return decorated_fn
        return decorator
    

    If you now try:

    @cache
    def some_method()
        pass
    

    You get an AssertionError on declaration.

    On a total tangent, I came across this post looking for decorators that decorate classes, rather than classes that decorate. In case anyone else does too, this question is useful.

提交回复
热议问题