当前位置: 首页 > news >正文

记忆化搜索@cache与自己创建一个字典进行存储有区别吗

在 Python 中,使用 functools.lru_cache(比如通过装饰器 @cache)和自己手动创建一个字典来进行 ​记忆化(Memoization)​,​本质上都是通过存储已经计算过的结果来避免重复计算,从而达到优化递归或重复调用性能的目的。但它们在使用方式、功能、灵活性和实现细节上有一些 ​重要区别


一、@cache(来自 functools)

@cache是 Python 3.9+ 中 functools模块提供的一个装饰器(在早期版本中是 lru_cache(maxsize=None)的简化版),它的作用是 ​自动缓存函数的输入参数和对应的返回值

特点:

  1. 1.

    自动管理缓存

    • 你不需要手动创建和管理字典,@cache内部帮你处理了输入 → 输出 的映射。

  2. 2.

    基于函数参数自动哈希

    • 它根据函数的 ​所有位置参数和关键字参数​ 自动生成一个缓存键(通常基于参数的哈希值)。

    • 因此,​只有参数是可哈希(hashable)的类型(比如数字、字符串、元组等),才能使用 @cache

  3. 3.

    使用简单,代码更干净

    from functools import cache@cache
    def fib(n):if n < 2:return nreturn fib(n-1) + fib(n-2)
  4. 4.

    线程安全

    • @cache是线程安全的,适合在多线程环境中使用。

  5. 5.

    不可自定义缓存策略

    • 比如你无法手动查看缓存、删除某个缓存项、限制缓存大小(除非用 lru_cache(maxsize=xxx)),也无法使用不可哈希的参数(如 list, dict)。


二、自己创建字典进行记忆化

这是更底层、更灵活的方式:​你自己定义一个字典,然后在函数内部手动检查是否已经计算过某个输入,如果计算过就直接返回缓存值,否则计算并存储

示例:

memo = {}def fib(n):if n in memo:return memo[n]if n < 2:result = nelse:result = fib(n-1) + fib(n-2)memo[n] = resultreturn result

或者更通用的方式,把 memo 放进函数内部(闭包或默认参数等方式):

def fib(n, memo={}):if n in memo:return memo[n]if n < 2:return nmemo[n] = fib(n-1, memo) + fib(n-2, memo)return memo[n]

注意:将 memo作为默认参数存在一定风险(因为默认参数在函数定义时只初始化一次),更推荐用闭包或者传入 dict。

特点:

  1. 1.

    灵活

    • 你可以控制缓存的结构,比如用多维键、非哈希对象作为键(虽然需要额外处理,比如转为可哈希结构如元组)。

    • 可以手动查看、删除缓存项,可以针对特定场景定制缓存逻辑。

  2. 2.

    需要手动管理

    • 你必须自己写代码去判断是否缓存过、存入缓存等,代码量稍多,也容易出错。

  3. 3.

    参数限制相对宽松(可定制)​

    • 如果你想要以不可哈希对象(如列表、字典)作为“参数”的依据,你可以 ​将这些参数转换为可哈希的形式(比如元组)​,然后自己管理映射关系。而 @cache是无法直接接受不可哈希参数的。

  4. 4.

    非线程安全(需自行处理)​

    • 如果在多线程环境中共享一个 memo 字典,需要加锁等手段保证安全,否则可能出现竞态条件。


三、主要区别总结

特性

@cachelru_cache

自己用字典做记忆化

使用难度

简单,一行装饰器

需要手动编写缓存逻辑

代码简洁性

高,函数本体更干净

相对冗长,尤其是处理缓存逻辑时

缓存管理

自动,不可直接干预

手动控制,可以更灵活

参数类型支持

只支持可哈希参数

可通过转换支持更复杂的参数(如将 list 转 tuple)

缓存查看/清除

可通过 cache_info()和 cache_clear()查看和清除

需要自己实现

线程安全

否(需自己加锁等处理)

适用场景

函数参数简单、可哈希,追求开发效率

需要高度定制化缓存逻辑、处理复杂参数或特殊需求


四、什么时候用哪种?

✅ 推荐使用 @cache的情况:

  • 你的函数参数是 ​可哈希的(比如数字、字符串、元组等)​

  • 你希望 ​代码简洁,不想手动管理缓存

  • 你只需要基本的记忆化功能,不需要干预缓存本身

  • 你使用的是 Python 3.9+(或用 lru_cache(maxsize=None)

✅ 考虑自己实现字典记忆化的情况:

  • 你的函数参数包含 ​不可哈希对象(如列表、字典、集合等)​,需要先转换为可哈希类型

  • 你想要 ​更灵活的缓存策略,比如基于某些条件缓存或不缓存

  • 你想要 ​手动查看、修改、删除缓存内容

  • 你可能在做一些 ​高级算法设计、动态规划调试,需要更直观地控制记忆过程

  • 你使用的是 ​Python 3.8 或更早版本,并且不想用 lru_cache


五、附加建议

  • 如果你用 Python 3.2+,可以使用 @functools.lru_cache(maxsize=None),它和 @cache几乎一样,只是 @cache是 maxsize=None的一个简化别名(Python 3.9+)。

  • 如果你在学习动态规划或递归优化,​建议先手动实现记忆化(用字典),这样能更深入理解其原理;熟悉之后再使用 @cache提高开发效率。

  • 如果你缓存的是复杂对象或想基于部分参数缓存,自己管理字典会更方便。


✅ 总结一句话:

@cache是 Python 提供的 ​自动化、简洁高效​ 的记忆化工具,适合大多数标准场景;而 ​自己创建字典进行记忆化更加灵活可控,适合需要定制化处理或参数复杂的场景。两者本质都是存储已计算结果以避免重复计算,但在易用性、灵活性和控制力上有明显区别。

http://www.dtcms.com/a/323737.html

相关文章:

  • 10.final, finally, finalize的区别
  • Level-MC 11“天空”
  • SpringBoot配置生效优先级
  • 实战:MyBatis 中 db.properties 的正确配置与最佳实践
  • 通过 SCP 和 LXD 配置迁移 CUDA 环境至共享(笔记)
  • HTML全景效果实现
  • C语言(长期更新)第9讲:操作符详解(一)
  • 《励曼旋耕》Liman Rotary Tillage
  • AI大模型模态特征详解
  • 功能测试中常见的面试题-一
  • 第4章 程序段的反复执行for语句P115练习题(题及答案)
  • C++面向对象及其特性
  • 大语言模型提示工程与应用:大语言模型进阶提示工程技术
  • 【LLM实战|langchain】langchain基础
  • 百度网盘自动启动如何关闭,关闭智能看图
  • Windows系统NUL文件删除问题解决
  • 【ref、toRef、toRefs、reactive】
  • C++学习之STL学习:map/set
  • openvela之ADB
  • Java Stream 使用 Fork/Join框架的分治任务模型
  • 详解Windows(十四)——PowerShell与命令提示符
  • 如何检查减速机的密封件是否老化?
  • 06-docker容器常用命令
  • Docker镜像地址
  • 安装NodeJS和TypeScript简要指南
  • MySQL数据库详细笔记
  • 线上排查问题的一般流程是怎么样的?
  • Linux网络子系统架构分析
  • 检索增强生成:RAG(Retrieval Augmented Generation)
  • doubletrouble靶机通关练习笔记