首页 > 编程问答 >如何缓存可变实例属性?

如何缓存可变实例属性?

时间:2024-08-07 14:56:52浏览次数:10  
标签:python properties memoization

我可以像这样缓存数据类的实例属性:

from dataclasses import dataclass
from functools import cached_property

@dataclass
class Point:
    _x: float

    @cached_property
    def x(self):
        return self._x * 2

>> p = Point(3)
>> p.x
6

我希望每次调用它时都将计算应用于 x ,使用缓存的结果进行后续调用以避免不必要的计算。

但我也想要改变 x 虽然 p.x += 1 适用于上面的代码,但很多地方都说 @cached_property 适用于不可变值。在我实际的、更复杂的代码中,它给了我奇怪的、难以理解的结果。我将此归因于当装饰器与可变属性一起使用时令人惊讶的行为(即使我不完全理解发生了什么)。

缓存在其整个生命周期中发生变化的实例属性的正确方法是什么?


你对 @cached_property 和可变性的担心是完全有道理的。尽管你的例子可以运行,但它依赖于微妙且容易出错的行为。让我们来分析一下问题所在,并探讨一些更强大的解决方案。

@cached_property 问题

@cached_property 的设计目的是用于计算结果仅依赖于不可变输入的属性。它通过在第一次调用时缓存属性的结果来工作。后续调用不会重新计算结果,而是返回缓存值。

在你的 Point 类中, x 依赖于 _x 。当执行 p.x += 1 时,实际上并没有改变 _x ;只是修改了缓存的 x 属性。这可能会导致与 _x 的实际值不一致,并且在更大的代码库中,这种不一致可能会变得难以跟踪。

缓存可变属性的解决方案

以下是缓存可变属性的一些更可靠的方法:

  1. 显式缓存管理:

与其依赖 @cached_property ,不如在需要时手动管理缓存。这可以通过在类中引入一个单独的缓存字典来完成:

```python class Point: def init (self, x): self._x = x self._cache = {}

   def x(self):
       if 'x' not in self._cache:
           self._cache['x'] = self._x * 2
       return self._cache['x']

   def update_x(self, new_x):
       self._x = new_x
       self._cache.pop('x', None)  # 使缓存失效

p = Point(3) print(p.x()) # 计算并缓存 print(p.x()) # 从缓存返回

p.update_x(5) print(p.x()) # 重新计算并缓存 ```

在这个例子中, x() 方法检查缓存中是否存在结果。如果存在,则返回缓存值。否则,将计算该值,将其存储在缓存中,然后返回。 update_x() 方法确保在 _x 发生更改时使缓存失效。

  1. 使用 lru_cache (对于计算成本高的属性):

如果计算属性的成本很高,并且希望缓存最近的结果,则可以使用 functools 模块中的 lru_cache 装饰器。 lru_cache 实现了 LRU(最近最少使用)缓存机制。

```python from functools import lru_cache

class Point: def init (self, x): self._x = x

   @lru_cache(maxsize=None)
   def x(self):
       return self._x * 2

p = Point(3) print(p.x()) print(p.x()) # 从缓存返回 ```

请注意, lru_cache 不会自动使属性的缓存失效。需要在修改 _x 时手动使缓存失效(例如,使用与之前类似的 update_x 方法)。

  1. 重新设计以获得不变性(如果可能):

如果可能,最好的解决方案是重新设计你的类以使用不可变数据结构。这将消除对缓存可变属性的需求,并使你的代码更易于推理。

请记住,为可变属性选择正确的缓存策略取决于你的具体需求和代码的复杂性。

标签:python,properties,memoization
From: 78841994

相关文章

  • 将普通 python 文件导入另一个文件时出现 AttributeError
    我是新手。我正在尝试将简单的python文件导入到我的主文件中。相同的代码在我的mac上工作,但在我的电脑上不起作用。我不断收到此错误消息。“AttributeError:模块‘logo’没有属性‘hammer_logo’”第一个文件拍卖.py代码importlogoprint(logo.hammer_logo)第......
  • 使用python读取mysql数据,并记录到本地的文件中
    上次写过一次读取sqlserver数据,写入本地文件。今天分享一下mysql的。原理相似,希望对大家有小小的帮忙PS,我是3.6.13版本python,上一版本用包mysql-connector,一直不成功,查询官方文档,发现这个版本的PYTHON简直是奇葩的存在了。基本所有版本都支持,就是几个小版本排除在外了。......
  • python合并音视频-通过moviepy模块合并音视频
    ......
  • esp32安装circuitpython
    安装Thonnyhttps://thonny.org/在Thonny中安装circuitpython在配置解释器中选择circuitython然后点击右下角“安装或更新...“variant这里我选择了DOITesp32DevelopmentBoard(试过其他的一些个,不知道为什么安装完之后会无限重启,所以最后选择了这个)烧录完之后,重新连接,Th......
  • 利用Python进行金融数据分析的全面指南【文末送书】
    文章目录Python金融数据分析技术文章Python金融数据分析【文末送书】Python金融数据分析技术文章金融数据分析在现代金融行业中扮演着至关重要的角色。通过使用Python编程语言,我们可以对大量金融数据进行处理、分析和可视化,从而获得有价值的洞察。本篇文章将介绍如何......
  • python和sliver交互
    开源第三方库:https://sliverpy.readthedocs.io/en/latest/getting-started.html#connect-example代码示例:importosimportasynciofromsliverimportSliverClientConfig,SliverClientCONFIG_PATH=os.path.join('../sliver/','moloch_127.0.0.1.cfg')......
  • 不写代码,这样使用Python seaborn、matplotlib
    今天分享一个PyQt5GUI工具,动动鼠标拖拽就使用Python的Matplotlib、Seaborn进行绘图,并导出高清PDF。sviewgui安装pip install sviewguisviewgui使用使用很简单,因为,他只有一个方法啊:buildGUI();下面以tips.csv数据和boxplot为例介绍sviewgui的使用。以下三种方法均可......
  • 零基础学习人工智能—Python—Pytorch学习(一)
    前言其实学习人工智能不难,就跟学习软件开发一样,只是会的人相对少,而一些会的人写文章,做视频又不好好讲。比如,上来就跟你说要学习张量,或者告诉你张量是向量的多维度等等模式的讲解;目的都是让别人知道他会这个技术,但又不想让你学。对于学习,多年的学习经验,和无数次的回顾学习过程,都......
  • 【Python】网络编程
    计算机网络的介绍计算机的发展经历了以下几个阶段:阶段时间物理器件第一阶段1946年到20世纪50年代后期电子管第二阶段20世纪50年代后期到20世纪60年代中期晶体管第三阶段20世纪60年代中期到20世纪70年代初期中小规模集成电路第四阶段20世纪70年代初期至今大规模集成电路1.通......
  • 猫头虎分享 Python 知识点:pandas--info()函数用法
    ......