You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python functools模块中lru_cache的内部工作原理探究

深入理解Python functools.lru_cache的内部实现

这个问题问得很到位!咱们来拆解一下functools.lru_cache的底层实现,把你的两个疑问讲清楚:

1. 它是否像Python其他组件一样使用字典?

是的,但它不是单纯用普通字典——为了实现LRU(最近最少使用)的淘汰策略,lru_cache结合了哈希表(字典)+ 双向链表的组合结构(Python 3.7及以后的版本里,OrderedDict本身就是基于这种结构实现的,早期的lru_cache直接依赖OrderedDict,后来的版本做了更高效的底层优化)。

  • 字典的核心作用是快速查找:把函数的输入参数转换成可哈希的键后,能在O(1)时间内找到对应的缓存值,这和普通字典的查找逻辑一致。
  • 双向链表则用来维护访问顺序:每次访问一个缓存项,就把它移到链表头部;当缓存达到设定的maxsize上限时,直接淘汰链表尾部的项(也就是最近最少被使用的那个)。

这里给你一个简化版的核心逻辑示意(不是实际源码,帮你理解核心思路):

# 简化版LRU缓存结构
class SimpleLRUCache:
    def __init__(self, maxsize):
        self.cache_map = dict()  # 存储参数键到(返回值, 链表节点)的映射
        self.access_list = DoublyLinkedList()  # 维护缓存项的访问顺序
        self.maxsize = maxsize

    def get(self, key):
        if key in self.cache_map:
            value, node = self.cache_map[key]
            self.access_list.move_to_head(node)  # 标记为最近使用
            return value
        return None

    def put(self, key, value):
        if key in self.cache_map:
            # 已存在的缓存项,更新值并移到头部
            node = self.cache_map[key][1]
            self.access_list.move_to_head(node)
            self.cache_map[key] = (value, node)
        else:
            # 新缓存项,先检查是否超容
            if len(self.cache_map) >= self.maxsize:
                # 淘汰最久未使用的项
                tail_node = self.access_list.remove_tail()
                del self.cache_map[tail_node.key]
            # 添加新项到头部
            new_node = self.access_list.add_to_head(key)
            self.cache_map[key] = (value, new_node)

实际的lru_cache源码会更复杂,比如要处理可哈希参数的校验、关键字参数的标准化(把*args和排序后的**kwargs组合成唯一的哈希键)、线程安全的同步等,但核心结构确实是哈希表+顺序维护结构。

2. 是否仅存储返回值?

当然不是!它存储的是参数键到返回值的映射,但为了实现LRU逻辑和统计功能,还会额外存储不少元数据:

  • 首先,它会把函数的输入参数(包括位置参数和关键字参数)转换成一个唯一的可哈希键(比如将args元组和排序后的kwargs键值对组合成新的元组),这个键是字典的key。
  • 对应的value部分,除了函数的返回值,还包含用于维护LRU顺序的信息(比如双向链表节点的引用、访问时间标记等)。
  • 另外,lru_cache还会自动维护缓存的统计数据:比如命中次数、未命中次数、当前缓存大小等,你可以通过cache_info()方法查看这些数据:
from functools import lru_cache

@lru_cache(maxsize=10)
def add(a, b):
    return a + b

add(1, 2)
add(1, 2)
print(add.cache_info())  # 输出:CacheInfo(hits=1, misses=1, maxsize=10, currsize=1)

这些统计数据也是lru_cache内部存储的额外信息,不属于函数的返回值,但对缓存的监控和调优非常有用。

内容的提问来源于stack exchange,提问作者innicoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:24:24