Use functools' @lru_cache without specifying maxsize parameter

后端 未结 3 836
遇见更好的自我
遇见更好的自我 2021-01-04 03:56

The documentation for lru_cache gives the function definition:

@functools.lru_cache(maxsize=128, typed=False)

Th

3条回答
  •  轻奢々
    轻奢々 (楼主)
    2021-01-04 04:11

    You have to at least call lru_cache without args:

    @lru_cache()
    def f():
        #content of the function
    

    This way, lru_cache is initialized with default parameters.

    This is because decorators in python (with the @ notation) are special functions which are evaluated and called when the interpreter is importing the module.

    When you write @decorator_name you tell python that decorator_name is a function that will be called with the function (or class) defined after. Example:

    @my_decorator
    def function():
        pass
    

    is equivalent to:

    def function():
        pass
    decorated_function = my_decorator(function)
    

    The lru_cache decorator is a little bit more complex because before wrapping the function, it has to create the cache (related to the function), and then wrap the function with another function that will do the cache management. Here is the (shorted) code of the CPython implementation :

    def lru_cache(maxsize=128, typed=False):
        # first, there is a test about the type of the parameters
        if maxsize is not None and not isinstance(maxsize, int):
            raise TypeError('Expected maxsize to be an integer or None')
        # then, the decorating function is created, this function will be called each time you'll call the 'cached' function
        def decorating_function(user_function):
            wrapper = _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo)  # in _lru_wrapper is all the magic about the cache management, it is a 2nd layer of decorator
            return update_wrapper(wrapper, user_function)
        return decorating_function
    

    So, when you wrote only

    @lru_cache
    def f():
    

    python called lru_cache(f), and definitively, it wasn't made to handle such thing.

    To make it compliant with this write, we should add a test to check if the first parameter (maxsize) is a callable function:

    def lru_cache(maxsize=128, typed=False):
        # first, there is a test about the type of the parameters
        if callable(maxsize):
            def decorating_function(user_function):
                wrapper = _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo)
                return update_wrapper(wrapper, user_function)
            return decorating_function(maxsize) # yes, maxsizeis the function in this case O:)
        if maxsize is not None and not isinstance(maxsize, int):
            raise TypeError('Expected maxsize to be an integer or None')
        # then, the decorating function is created, this function will be called each time you'll call the 'cached' function
        def decorating_function(user_function):
            wrapper = _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo)  # in _lru_wrapper is all the magic about the cache management, it is a 2nd layer of decorator
            return update_wrapper(wrapper, user_function)
        return decorating_function
    

提交回复
热议问题