documentation for lru_cache
给出了函数定义:
@functools.lru_cache(maxsize=128, typed=False)
这告诉我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
>>>
使用参数调用很好:
>>> @functools.lru_cache(8)
... def f(): ...
...
>>>
我误读了文档吗?
答案 0 :(得分:8)
你必须至少在没有args的情况下调用lru_cache:
@lru_cache()
def f():
#content of the function
这样,lru_cache用默认参数初始化。
这是因为python中的装饰器(带有@
表示法)是特殊函数,在解析器读取源时会对其进行求值和调用。
当您编写@decorator_name
时,您告诉python decorator_name
是一个将使用之后定义的函数(或类)调用的函数。
示例:
@my_decorator
def function():
pass
相当于:
def function():
pass
decorated_function = my_decorator(function)
lru_cache
装饰器有点复杂,因为在包装函数之前,它必须创建缓存(与函数相关),然后用另一个将执行缓存管理的函数包装该函数。
以下是CPython implementation :( / p>)的(简短)代码
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
所以,当你只写
时@lru_cache
def f():
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
答案 1 :(得分:2)
在Python 3.8+上,您可以不带括号地使用@lru_cache
,因此您的代码段可以正常工作
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
...
>>>
在Python 3.7或更低版本上,您必须做@lru_cache()
(在@lru_cache
之后加上括号)。
它是在2019年5月26日提交的b821868e6d909f4805499db519ebc2cdc01cf611
中添加的。
答案 2 :(得分:0)
这样想:lru_cache是一个装饰工厂。你打电话给它(有或没有参数,但你打电话给它),它给你一个装饰。
调用装饰器工厂并在一行上应用装饰器相当于:
with_small_cache = lru_cache(max_size=5)
@with_small_cache
def function():
...