【问题标题】:Pythons lru_cache on inner function doesn't seem to work内部函数上的 Python lru_cache 似乎不起作用
【发布时间】:2020-11-07 02:46:00
【问题描述】:

我正在尝试使用functools.lru_cache 来缓存内部函数的结果,但缓存似乎没有按预期工作。

我有一个执行一些逻辑的函数,然后调用一个相当昂贵的函数。我想缓存昂贵的函数调用的结果,尽管我只是将lru_cache 应用于内部函数。不幸的是,行为并不像预期的那样 - 即使内部函数的参数相同,每次都会调用昂贵的函数。

我创建了一个(简化的)测试用例来显示行为:

import unittest
from functools import lru_cache
from unittest.mock import patch

def expensive_function(parameter: str) -> str:
    return parameter

def partially_cached(some_parameter: str) -> str:

    @lru_cache
    def inner_function(parameter: str):
        return expensive_function(parameter)

    result = inner_function(some_parameter)

    print(inner_function.cache_info())

    return result

class CacheTestCase(unittest.TestCase):

    def test_partially_cached(self):
        
        with patch(self.__module__ + ".expensive_function") as expensive_mock:

            expensive_mock.return_value = "a"

            self.assertEqual(partially_cached("a"), "a")
            self.assertEqual(partially_cached("a"), "a")

            # If the cache works, I expect the expensive function
            # to be called just once for the same parameter
            expensive_mock.assert_called_once()

if __name__ == "__main__":
    unittest.main()

(在这种情况下,我不需要内部函数,但正如我所说 - 它被简化了)

不幸的是,测试失败了

python3 /scratch/test_cache.py
CacheInfo(hits=0, misses=1, maxsize=128, currsize=1)
CacheInfo(hits=0, misses=1, maxsize=128, currsize=1)
F
======================================================================
FAIL: test_partially_cached (__main__.CacheTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
[...]
AssertionError: Expected 'expensive_function' to have been called once. Called 2 times.
Calls: [call('a'), call('a')].

----------------------------------------------------------------------
Ran 1 test in 0.004s

FAILED (failures=1)

我可能对内部函数或 lru_cache 有误解,但我不确定它是哪一个 - 感谢我能得到的所有帮助。

【问题讨论】:

    标签: python python-3.x caching


    【解决方案1】:

    它不能按预期工作,因为每次调用 partially_cached 时都会重新定义 inner_function,缓存版本也是如此。所以每个缓存的版本只被调用一次。

    memoizing-decorator-keeping-stored-values

    另外,如果你模拟一个装饰函数,你需要再次应用装饰器。

    how-to-mock-a-decorated-function

    如果你在外层装饰,或者装饰另一个提取到外层的函数,它会起作用,如果你不通过模拟来破坏它。

    【讨论】:

      猜你喜欢
      • 2018-08-11
      • 1970-01-01
      • 2014-03-20
      • 2015-06-29
      • 1970-01-01
      • 2022-12-03
      • 2019-04-23
      • 2010-11-03
      • 2013-06-19
      相关资源
      最近更新 更多