为什么 'functools.cache' 和 'functools.lru_cache' 不适用于 class 方法中的内部函数?

Why does 'functools.cache' and 'functools.lru_cache' not working for inner function inside class method?

为什么 functools.cachefunctools.lru_cache 不适用于 class 方法中的内部函数?在不安装 3rd 方包并且不将内部函数移动到外部范围的情况下是否有任何解决方法?

from functools import cache

class Sample:

    def outer(self, a):
        @cache
        def inner(b):
            print(f"Inner function is called! b: '{b}'")
            return b

        return inner(a)


sample = Sample()
sample.outer(100)
sample.outer(100)
sample.outer(100)

输出:

Inner function is called! b: '100'
Inner function is called! b: '100'
Inner function is called! b: '100'

我希望内部函数对同一个参数只调用一次。

据推测,每次调用 outer 时,inner 函数都会获取“re-created”,导致缓存不再起作用。这个例子证实了这一点,它从 outer:

多次调用 inner
from functools import cache

class Sample:

    def outer(self, a):
        @cache
        def inner(b):
            print(f"Inner function is called! b: '{b}'")
            return b

        for i in range(3):
            print(f"Inner call #{i}")
            print(inner(a))
        return 

sample = Sample()
sample.outer(100)
sample.outer(100)
sample.outer(100)

输出:

Inner call #0
Inner function is called! b: '100'
100
Inner call #1
100
Inner call #2
100
Inner call #0
Inner function is called! b: '100'
100
Inner call #1
100
Inner call #2
100
Inner call #0
Inner function is called! b: '100'
100
Inner call #1
100
Inner call #2
100

因此,缓存 确实 起作用,但仅在 inner class 为“re-created” 之前有效。一个非常简单的解决方案是避免使用内部函数,而是依赖以下静态函数:

from functools import cache

class Sample:

    @staticmethod
    @cache
    def _inner(b):
        print(f"Inner function is called! b: '{b}'")
        return b

    def outer(self, a):
        for i in range(3):
            print(f"Inner call #{i}")
            print(Sample._inner(a))
        return 

sample = Sample()
sample.outer(100)
sample.outer(100)
sample.outer(100)

请注意,我已将 inner 重命名为 _inner,以表明 _inner 不打算暴露给 class 的用户。此外,我把它变成了静态方法。这允许您使用 Sample._inner(...) 而不是 self._inner(...)。毕竟self参数没有在_inner中使用,所以可以是静态函数

这输出(期望的):

Inner call #0
Inner function is called! b: '100'
100
Inner call #1
100
Inner call #2
100
Inner call #0
100
Inner call #1
100
Inner call #2
100
Inner call #0
100
Inner call #1
100
Inner call #2
100

这表明已为不同的 outer 调用正确缓存所有内容。