python decorator arguments with @ syntax

前端 未结 1 1234
闹比i
闹比i 2021-01-18 02:29

I\'m trying to use a cached property decorator that can take arguments.

I looked at this implementation: http://www.daniweb.com/software-development/python/code/2172

相关标签:
1条回答
  • 2021-01-18 03:00

    You need a decorator factory, another wrapper that produces the decorator:

    from functools import wraps 
    
    def cachedProperty(name=None):
        def decorator(func):
            if decorator.name is None:
                decorator.name = func.__name__ 
            @wraps(func)
            def _get(self):
                try:
                    return self.__dict__[decorator.name]
                except KeyError:
                    value = func(self)
                self.__dict__[decorator.name] = value 
                return value 
            def _del(self):
                self.__dict__.pop(decorator.name, None)
            return property(_get, None, _del)
        decorator.name = name
        return decorator
    

    Use this as:

    @cachedProperty(name='test')
    def my_func(self):
        return 'ok'
    

    A decorator is really just syntactic sugar for:

    def my_func(self):
        return 'ok'
    my_func = cachedProperty(name='test')(my_func)
    

    so as long as the expression after @ returns your decorator [*] it doesn't matter what the expression itself actually does.

    In the above example, the @cachedProperty(name='test') part first executes cachedProperty(name='test'), and the return value of that call is used as the decorator. In the above example, decorator is returned, so the my_func function is decorated by calling decorator(my_func), and the return value of that call is property object, so that is what'll replace my_func.


    [*] The @ expression syntax is deliberately limited in how much it is allowed to do. You can do attribute lookups and calls, that's it, the decorator grammar rule only allows an optional call with arguments at the end of a dotted name (where dots are optional):

    decorator               ::=  "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE)
    

    This is a deliberate limitation of the syntax.

    0 讨论(0)
提交回复
热议问题