使用functools的@lru_cache而不指定maxsize参数

Tom*_*ale 5 python caching lru functools

给出函数定义的文档lru_cache:

@functools.lru_cache(maxsize=128, typed=False)
Run Code Online (Sandbox Code Playgroud)

这对我说maxsize是可选的.

但是,它不喜欢没有参数调用:

Python 3.6.3 (default, Oct 24 2017, 14:48:20) 
[GCC 7.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import functools
>>> @functools.lru_cache
... def f(): ...
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.6/functools.py", line 477, in lru_cache
    raise TypeError('Expected maxsize to be an integer or None')
TypeError: Expected maxsize to be an integer or None
 >>> 
Run Code Online (Sandbox Code Playgroud)

使用参数调用很好:

>>> @functools.lru_cache(8)
... def f(): ...
... 
>>> 
Run Code Online (Sandbox Code Playgroud)

我误读了文档吗?

Bor*_*ris 13

Starting with Python 3.8+ you can use @lru_cache without parentheses, so your code snippet will work as-is

Python 3.8.0 (default, Oct 28 2019, 16:14:01) 
[GCC 9.2.1 20191008] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import functools
>>> @functools.lru_cache
... def f():
...     return 2
... 
>>> 
Run Code Online (Sandbox Code Playgroud)

On older versions of Python (i.e. 3.7 or below) you have to do @lru_cache(). As in, add parentheses after @lru_cache

PS. @lru_cache with no arguments implicitly sets max_size to 128. If you want to use a cache with no max size instead, on Python 3.9 you can use the new functools.cache decorator, which acts like lru_cache(max_size=None).


Céd*_*ien 10

你必须至少调用没有args的lru_cache:

@lru_cache()
def f():
    #content of the function
Run Code Online (Sandbox Code Playgroud)

这样,lru_cache就会使用默认参数进行初始化.

这是因为python中的装饰器(带@符号)是特殊函数,在解析器读取源时会对其进行求值和调用.

当你写的时候@decorator_name告诉python这decorator_name是一个将使用之后定义的函数(或类)调用的函数.例:

@my_decorator
def function():
    pass
Run Code Online (Sandbox Code Playgroud)

相当于:

def function():
    pass
decorated_function = my_decorator(function)
Run Code Online (Sandbox Code Playgroud)

lru_cache装饰是更复杂一点,因为包装的功能之前,必须创建高速缓存(相关功能),然后用另一个函数,将做缓存管理包的功能.这是CPython实现的(简短)代码:

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
Run Code Online (Sandbox Code Playgroud)

所以,当你只写时

@lru_cache
def f():
Run Code Online (Sandbox Code Playgroud)

python被称为lru_cache(f),并且最终,它没有被处理这样的事情.

为了使其符合此写入,我们应该添加一个测试来检查第一个参数(maxsize)是否是可调用函数:

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
Run Code Online (Sandbox Code Playgroud)

  • 对我来说,Least Surprise说大多数装饰者不需要`()`之后......我真的很喜欢你所做的并不需要它们. (2认同)