Python中的装饰器`@functools.lru_cache`:用法、来源与应用 (中英双语)

今天看到一段源码 https://github.com/google-research/google-research/blob/master/instruction_following_eval/instructions_util.py 如下,对其中使用的装饰器函数感到好奇,所以产生了这篇博客。


@functools.lru_cache(maxsize=None)
def _get_sentence_tokenizer():return nltk.data.load("nltk:tokenizers/punkt/english.pickle")

Python中的@functools.lru_cache:用法、来源与应用

在Python中,@装饰器语法的标志,用于将一个函数包装进另一个函数中,扩展或修改其功能。functools.lru_cache是Python标准库functools模块提供的一个装饰器,用于缓存函数的返回值,提升性能。


1. 装饰器的来源与语法

装饰器(Decorators)是Python函数式编程的一个核心特性。其来源可以追溯到Python 2.4版本,主要目的是让代码更简洁、更易读。@符号将装饰器函数与目标函数绑定,简化代码调用。

  • 装饰器定义
    本质上,装饰器是一个接收函数作为参数并返回一个新函数的高阶函数

示例:

def decorator(func):def wrapper():print("装饰器已执行")return func()return wrapper@decorator  # 等价于 func = decorator(func)
def say_hello():print("Hello, World!")

更多关于python装饰器的内容,可以参考笔者的另一篇博客:什么是装饰器?以Python为例:Basic Usage of Decorators (中英双语)


2. functools.lru_cache的作用

functools.lru_cache 是一个用于缓存函数调用结果的装饰器。

  • LRU全称是Least Recently Used,即最近最少使用缓存策略。
  • 当函数被多次调用时,lru_cache会缓存函数的输入和输出,减少重复计算,提升效率。
参数说明
  • maxsize: 设置缓存大小(None表示无限制)。
  • typed: 是否区分输入参数的类型(默认为False)。

示例:

import functools@functools.lru_cache(maxsize=3)
def fibonacci(n):print(f"计算Fibonacci({n})")if n < 2:return nreturn fibonacci(n-1) + fibonacci(n-2)print(fibonacci(5))  # 计算结果缓存,重复调用时不会重新计算

输出示例:

计算Fibonacci(5)
计算Fibonacci(4)
计算Fibonacci(3)
计算Fibonacci(2)
计算Fibonacci(1)
计算Fibonacci(0)
5

3. 代码分析与解释

以下是https://github.com/google-research/google-research/blob/master/instruction_following_eval/instructions_util.py 提供的代码:

import functools
import nltkdef count_words(text):"""Counts the number of words."""tokenizer = nltk.tokenize.RegexpTokenizer(r"\w+")tokens = tokenizer.tokenize(text)num_words = len(tokens)return num_words@functools.lru_cache(maxsize=None)
def _get_sentence_tokenizer():return nltk.data.load("nltk:tokenizers/punkt/english.pickle")
代码解释:
  1. count_words函数

    • 用于统计文本中的单词数量。
    • 通过nltk库中的RegexpTokenizer按正则表达式匹配单词,返回token列表并计算长度。
  2. _get_sentence_tokenizer函数

    • 加载NLTK库的句子分割模型punkt
    • 使用@functools.lru_cache(maxsize=None)装饰,表示缓存该函数的返回值。
    • 好处:加载分词器的操作是耗时的,通过缓存,只需加载一次。

4. functools.lru_cache的应用场景

  • 递归函数:如斐波那契数列,避免重复计算。
  • I/O密集型函数:比如数据库查询、网络请求,缓存结果以减少耗时。
  • 大规模数据处理:缓存部分中间结果,提高性能。
  • 机器学习/自然语言处理:模型加载、分词器初始化等耗时操作。

示例:

@functools.lru_cache(maxsize=128)
def fetch_data_from_db(query):# 模拟数据库查询print("执行查询:", query)return f"结果_{query}"print(fetch_data_from_db("SELECT * FROM table"))
print(fetch_data_from_db("SELECT * FROM table"))  # 直接返回缓存结果

输出:

执行查询: SELECT * FROM table
结果_SELECT * FROM table
结果_SELECT * FROM table

5. 补充内容:查看缓存信息

functools.lru_cache 提供了缓存管理的方法:

  • cache_info():查看缓存命中率和状态。
  • cache_clear():清空缓存。

示例:

@functools.lru_cache(maxsize=2)
def add(a, b):return a + badd(1, 2)
add(3, 4)
add(5, 6)print(add.cache_info())  # 输出缓存状态
add.cache_clear()        # 清除缓存

总结

  1. 装饰器的语法@用来将装饰器与函数绑定。
  2. lru_cache作用:缓存函数结果,提升性能,避免重复计算。
  3. 实际应用:适用于递归计算、I/O密集型操作和数据处理任务。
  4. 代码示例:通过数值分析,展示了lru_cache的高效性。

通过合理使用functools.lru_cache,Python程序可以在性能瓶颈处得到极大提升。

英文版

Exploring @functools.lru_cache in Python

The @ symbol in Python is used for decorators, which allow you to modify or enhance the behavior of a function or method. One such decorator is functools.lru_cache, which caches a function’s return values for optimized performance, especially in repetitive or resource-intensive tasks.


What is lru_cache?

functools.lru_cache is part of Python’s functools module. LRU stands for Least Recently Used, a caching strategy that keeps only the most frequently or recently used results, removing older ones when the cache exceeds its size limit.

Key Syntax:

@functools.lru_cache(maxsize=None, typed=False)
Parameters:
  1. maxsize: The maximum number of results to cache. If set to None, the cache size is unlimited.
  2. typed: If True, different types of arguments (e.g., 1 vs. 1.0) will have separate cached results.

Code Example and Explanation

Here is an example of lru_cache in action: Source: https://github.com/google-research/google-research/blob/master/instruction_following_eval/instructions_util.py

import functools
import nltkdef count_words(text):"""Counts the number of words."""tokenizer = nltk.tokenize.RegexpTokenizer(r"\w+")tokens = tokenizer.tokenize(text)num_words = len(tokens)return num_words@functools.lru_cache(maxsize=None)
def _get_sentence_tokenizer():return nltk.data.load("nltk:tokenizers/punkt/english.pickle")
Breakdown:
  1. count_words:

    • Uses RegexpTokenizer from NLTK to split a text into tokens (words).
    • Computes and returns the word count.
  2. _get_sentence_tokenizer:

    • Loads NLTK’s pre-trained sentence tokenizer. This is resource-heavy if loaded multiple times.
    • Why use @lru_cache?:
      • With lru_cache, the tokenizer is loaded only once. Future calls retrieve it from the cache, saving time and memory.

How lru_cache Works

Internally, lru_cache uses a dictionary-like data structure to store results. When a function is called:

  1. The function’s arguments act as a unique key.
  2. If the result exists in the cache (cache hit), it is returned directly.
  3. If not (cache miss), the function computes the result, stores it in the cache, and returns it.

Practical Applications

  1. Recursive Calculations:

    @functools.lru_cache(maxsize=128)
    def fibonacci(n):if n < 2:return nreturn fibonacci(n - 1) + fibonacci(n - 2)
    

    In this example, repeated calls to the same input are avoided by caching results.

  2. Optimizing Expensive Operations: Tasks like API calls, database queries, or loading large models can benefit greatly from caching.


Why Use lru_cache?

  1. Performance Boost: Speeds up applications by avoiding redundant computations.
  2. Memory Efficiency: Automatically clears old entries when the cache limit is reached.
  3. Flexibility: It works with various types of functions and arguments.

Summary

@functools.lru_cache is a powerful tool for improving Python application efficiency. By caching results of expensive or repetitive function calls, it saves time and computational resources. Its ease of use and wide applicability make it an essential feature for developers.

后记

2024年12月16日19点49分于上海,在GPT4o大模型辅助下完成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/64298.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

三维空间刚体运动4-1:四元数表示变换(各形式相互转换加代码——下篇)

三维空间刚体运动4-1&#xff1a;四元数表示变换&#xff08;各形式相互转换加代码——下篇&#xff09; 4. 四元数到其它旋转表示的相互转换4.1 旋转向量4.2 旋转矩阵4.3 欧拉角4.3.1 转换关系4.3.2 转换中的万象锁问题 5. 四元数的其他性质5.1 旋转的复合5.2 双倍覆盖5.3 指数…

使用layui的table提示Could not parse as expression(踩坑记录)

踩坑记录 报错图如下 原因&#xff1a; 原来代码是下图这样 上下俩中括号都是连在一起的&#xff0c;可能导致解析问题 改成如下图这样 重新启动项目&#xff0c;运行正常&#xff01;

大模型的构建与部署(2)——数据清洗

版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl1. 数据清洗的必要性与影响 1.1 数据清洗对模型性能的影响 数据清洗是数据预处理的关键步骤,对于模型训练的性能和准确性有着直接的影响。原始数据中的缺失值、重复值、异常值以及数据格式不一致…

【MySQL】--- 数据库基础

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; MySQL 本篇博客我们来建立一下数据库的相关概念&#xff0c;主要理解什么是数据库以及mysql和mysqld&#xff0c;MySQL架构等问题。 &#x1f3e0; 登录…

Vue中纯前端实现导出简单Excel表格的功能

Vue 前端Excel导出 Vue中纯前端导出简单Excel表格的方法(使用vue-json-excel插件) 前言 在许多的后台系统中少不了导出Excel表格的功能&#xff0c;在项目中纯前端使用vue-json-excel插件来实现简单Excel表格的导出功能。 使用方法 1、安装依赖 npm install vue-json-exc…

3.1 角度

一、源码 use crate::approxeq::ApproxEq; use crate::trig::Trig;use core::cmp::{Eq, PartialEq}; use core::hash::Hash; use core::iter::Sum; use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, Sub, SubAssign};#[cfg(feature "bytemuc…

【深入理解Java线程池】

深入理解Java线程池 Java线程池是Java并发编程中的一个重要概念&#xff0c;它提供了一种管理和复用线程的机制&#xff0c;可以显著减少创建和销毁线程的开销&#xff0c;提高系统的响应速度和吞吐量。以下是对Java线程池的详细解析&#xff1a; 一、线程池的基本概念 线程…

KeyFormer:使用注意力分数压缩KV缓存

Keyformer: KV Cache Reduction through Key Tokens Selection for Efficient Generative Inference 202403&#xff0c;发表在Mlsys Introduction 优化KV cache的策略&#xff0c;主要是集中在系统级别的优化上&#xff0c;比如FlashAttention、PagedAttention&#xff0c;它…

Linux 权限管理实践:精确控制用户对 systemctl 和 journalctl 命令的使用

前言 在 Linux 系统管理中&#xff0c;精确控制用户对特定命令的访问权限是一项关键的安全实践。使用 systemctl 和 journalctl 命令时&#xff0c;不当的权限设置可能会导致不必要的风险。本篇博客将详细讨论如何通过 sudoers 文件和 Polkit 策略为不同用户配置 systemctl 和…

SSH连接成功,但VSCode连接不成功

环境 在实验室PC上连接服务器234 解决方案&#xff1a;在VSCode中重新添加远程主机 删除旧的VSCode Server 在远程主机上&#xff0c;VSCode会安装一个‘vscode-server’服务来支持远程开发&#xff0c;有时旧的‘vscode-server’文件可能会导致问题&#xff0c;删除旧的&am…

【Qt】qt安装

在工作一年之后&#xff0c;还是想做一个Qt的教程&#xff0c;遥想研一刚刚接触Qt&#xff0c;从0到1学习&#xff0c;没有什么参考书籍&#xff0c;网上的资料也不多&#xff0c;幸好Qt官方文档写得好&#xff0c;加上自己肯研究&#xff0c;才堪堪入门。 现在我想自己写一个…

Web开发 -前端部分-CSS

CSS CSS&#xff08;Cascading Style Sheet&#xff09;:层叠样式表&#xff0c;用于控制页面的样式&#xff08;表现&#xff09;。 一 基础知识 1 标题格式 标题格式一&#xff1a; 行内样式 <!DOCTYPE html> <html lang"en"><head><meta…

YOLOv8目标检测(六)_封装API接口

YOLOv8目标检测(一)_检测流程梳理&#xff1a;YOLOv8目标检测(一)_检测流程梳理_yolo检测流程-CSDN博客 YOLOv8目标检测(二)_准备数据集&#xff1a;YOLOv8目标检测(二)_准备数据集_yolov8 数据集准备-CSDN博客 YOLOv8目标检测(三)_训练模型&#xff1a;YOLOv8目标检测(三)_训…

MySQL函数—合计统计函数

在MySQL中&#xff0c;你可以使用合计统计函数来计算某个列的合计值、平均值、最大值、最小值等。这些合计统计函数包括SUM、AVG、MAX、MIN等。 下面是一些常用的合计统计函数的示例&#xff1a; SUM函数&#xff1a;用于计算某个列的合计值。 SELECT SUM(column_name) FROM…

51c视觉~YOLO~合集6~

我自己的原文哦~ https://blog.51cto.com/whaosoft/12830685 一、其他yolo 1.1 Spiking-YOLO​ 使用常规深度神经网络到脉冲神经网络转换方法应用于脉冲神经网络域时&#xff0c;性能下降的很多&#xff0c;深入分析后提出了可能的解释&#xff1a;一是来自逐层归一化的效率…

Unity3D 3D模型/动画数据压缩详解

前言 在Unity3D项目中&#xff0c;3D模型和动画数据通常占用大量内存和存储空间&#xff0c;有效的数据压缩技术对于提升游戏性能和加载速度至关重要。本文将详细介绍Unity3D中3D模型和动画数据的压缩技术&#xff0c;并提供相关的代码实现。 对惹&#xff0c;这里有一个游戏…

Elasticsearch Java Api Client中DSL语句的查询方法汇总(二)

接上一篇&#xff1a;《Elasticsearch Java Api Client中DSL语句的查询方法汇总》 说明&#xff1a;示例代码依赖的是co.elastic.clients:elasticsearch-java:8.16.1。 1、ScriptQuery方法 用途&#xff1a;它允许用户使用脚本&#xff08;通常是 Painless 脚本语言&#xf…

如何在 Ubuntu 22.04 上安装 Strapi CMS

简介 Strapi 是一个使用 JavaScript 构建的开源、无头内容管理系统 (CMS)。与其他无头 CMS 一样&#xff0c;Strapi 开箱即用不带前端。它使用 API 作为其前端&#xff0c;允许你使用流行的框架&#xff08;如 React 和 Next.js&#xff09;构建网站。Strapi 基于插件系统&…

数字IC后端零基础入门基础理论(Day1)

数字IC后端设计导入需要用到的input数据如下图所示。 数字后端零基础入门系列 | Innovus零基础LAB学习Day9 Netlist: 设计的Gate level&#xff08;门级&#xff09;网表。下图所示为一个计数器设计综合后的门级netlist。 从这个netlist中我们看到这个设计顶层的名字叫counte…

序列模型的使用示例

序列模型的使用示例 1 RNN原理1.1 序列模型的输入输出1.2 循环神经网络&#xff08;RNN&#xff09;1.3 RNN的公式表示2 数据的尺寸 3 PyTorch中查看RNN的参数4 PyTorch中实现RNN&#xff08;1&#xff09;RNN实例化&#xff08;2&#xff09;forward函数&#xff08;3&#xf…