为什么functools.lru_缓存破坏这个功能?

2024-04-20 05:01:41 发布

您现在位置:Python中文网/ 问答频道 /正文

考虑以下函数,它返回一组元素的所有唯一置换:

def get_permutations(elements):
    if len(elements) == 0:
        yield ()
    else:
        unique_elements = set(elements)
        for first_element in unique_elements:
            remaining_elements = list(elements)
            remaining_elements.remove(first_element)
            for subpermutation in get_permutations(tuple(remaining_elements)):
                yield (first_element,) + subpermutation

for permutation in get_permutations((1, 1, 2)):
    print(permutation)

这个指纹

^{pr2}$

一如预期。但是,当我添加lru_cache修饰符时,它会记住函数:

import functools

@functools.lru_cache(maxsize=None)
def get_permutations(elements):
    if len(elements) == 0:
        yield ()
    else:
        unique_elements = set(elements)
        for first_element in unique_elements:
            remaining_elements = list(elements)
            remaining_elements.remove(first_element)
            for subpermutation in get_permutations(tuple(remaining_elements)):
                yield (first_element,) + subpermutation

for permutation in get_permutations((1, 1, 2)):
    print(permutation)

它打印以下内容:

(1, 1, 2)

为什么只打印第一个排列?在


Tags: 函数inforgetifdefelementselement
1条回答
网友
1楼 · 发布于 2024-04-20 05:01:41

lru.cache记录函数的返回值。函数返回生成器。生成器有状态并且可以被耗尽(即,当你到达它们的末尾时,不再产生任何物品)。与函数的未修饰版本不同,每次使用给定的参数集调用函数时,LRU缓存将为您提供完全相同的生成器对象。最好是这样,因为这就是它的目的!在

但是您缓存的一些生成器被多次使用,并且在第二次及以后使用时部分或完全耗尽。(他们甚至可能不止一次同时“在游戏中”。)

要解释您得到的结果,请考虑当elements的长度为0而您yield ()时会发生什么。。。第一次。下一次调用此生成器时,它已经在末尾,根本不产生任何结果。因此,你的子置换循环什么都不做,也不会从中产生任何进一步的结果。由于这是递归中的“触底”情况,它对程序的运行至关重要,丢失它会破坏程序产生期望值的能力。在

(1,)的生成器也使用了两次,这在第三个结果降到{}之前就破坏了。在

要查看发生了什么,请在函数中添加一个print(elements)作为第一行(并在主for循环中的print调用中添加某种标记,这样就可以分辨出它们之间的区别)。然后比较记忆版本和原始版本的输出。在

似乎你想用某种方法来记忆生成器的结果。在这种情况下,您要做的是将它编写为一个函数,该函数返回一个包含所有项的列表(而不是一次生成一个项ts)并将其记下来。在

相关问题 更多 >