cached-property - 类属性缓存装饰器

本文翻译整理自:https://github.com/pydanny/cached-property

文章目录


一、关于 cached-property

cached-property 是一个用于缓存类属性的装饰器工具。


相关链接资源


关键功能特性

  • 快速简便地缓存耗时或计算密集型的类属性
  • 支持 Python 2 和 3(Python 3.8+ 已内置类似功能)
  • 提供线程安全版本 threaded_cached_property
  • 支持异步属性缓存
  • 可设置缓存超时时间(TTL)

二、安装

shell 复制代码
pip install cached-property

三、使用指南


1、基础用法

定义包含昂贵计算属性的类:

python 复制代码
class Monopoly:

    def __init__(self):
        self.boardwalk_price = 500

    @property
    def boardwalk(self):
        # 模拟耗时操作(如数据库查询或API调用)
        self.boardwalk_price += 50
        return self.boardwalk_price

测试效果(每次访问属性值都会变化):

python 复制代码
>>> monopoly = Monopoly()
>>> monopoly.boardwalk
550
>>> monopoly.boardwalk
600

转换为缓存属性:

python 复制代码
from cached_property import cached_property

class Monopoly(object):

    def __init__(self):
        self.boardwalk_price = 500

    @cached_property
    def boardwalk(self):
        self.boardwalk_price += 50
        return self.boardwalk_price

测试效果(值被缓存):

python 复制代码
>>> monopoly = Monopoly()
>>> monopoly.boardwalk
550
>>> monopoly.boardwalk  # 缓存生效
550

2、手动清除缓存

通过删除实例字典中的属性来清除缓存:

python 复制代码
>>> del monopoly.__dict__['boardwalk']
>>> monopoly.boardwalk  # 重新计算
600

3、线程安全版本

多线程环境下使用 threaded_cached_property

python 复制代码
from cached_property import threaded_cached_property

class Monopoly:

    def __init__(self):
        self.boardwalk_price = 500

    @threaded_cached_property
    def boardwalk(self):
        sleep(1)
        self.boardwalk_price += 50
        return self.boardwalk_price

多线程测试:

python 复制代码
>>> from threading import Thread
>>> threads = []
>>> for x in range(10):
>>>     thread = Thread(target=lambda: monopoly.boardwalk)
>>>     thread.start()
>>>     threads.append(thread)
>>> [t.join() for t in threads]
>>> assert monopoly.boardwalk == 550  # 确保线程安全

4、异步支持

缓存异步属性:

python 复制代码
from cached_property import cached_property

class Monopoly:

    def __init__(self):
        self.boardwalk_price = 500

    @cached_property
    async def boardwalk(self):
        self.boardwalk_price += 50
        return self.boardwalk_price

异步调用示例:

python 复制代码
>>> async def print_boardwalk():
...     monopoly = Monopoly()
...     print(await monopoly.boardwalk)
...     print(await monopoly.boardwalk)  # 使用缓存值
>>> asyncio.get_event_loop().run_until_complete(print_boardwalk())
550
550

注:异步版本不适用于多线程环境。


5、缓存超时(TTL)

设置缓存自动失效时间:

python 复制代码
from cached_property import cached_property_with_ttl

class Monopoly(object):

    @cached_property_with_ttl(ttl=5)  # 5秒后缓存失效
    def dice(self):
        return random.randint(2,12)

测试效果:

python 复制代码
>>> monopoly = Monopoly()
>>> monopoly.dice
10
>>> monopoly.dice  # 5秒内使用缓存
10
>>> sleep(6)      # 等待缓存过期
>>> monopoly.dice  # 重新计算
3

注:TTL 功能可能存在缓存清除不彻底的问题。


四、致谢

  • 感谢 Pip、Django、Werkzeug 等项目的类似实现
  • Reinout Van Rees 推荐原始装饰器方案
  • @tinche 提供线程安全解决方案
  • @bcho 贡献 TTL 功能

伊织 xAI 2025-04-27(日)

相关推荐
小熊Coding18 分钟前
Python爬取当当网二手图书项目实战!
开发语言·爬虫·python·beautifulsoup·requests·二手图书
秋922 分钟前
Java项目运行5天左右自动宕机:系统性定位与解决方案
java·开发语言·python
小江的记录本27 分钟前
【JVM虚拟机】垃圾回收GC:垃圾收集器:CMS:核心原理、回收流程、优缺点、废弃原因(附《思维导图》+《面试高频考点清单》)
java·jvm·后端·python·spring·面试·maven
cfm_291439 分钟前
Redis数据安全性解析
数据库·redis·缓存
田里的水稻1 小时前
OE_ubuntu26.04与宿主机之间复制粘贴内容
人工智能·python·机器人
jiayong232 小时前
02 创建虚拟环境
python
辞忧九千七2 小时前
Redis 单机一主二从主从复制完整搭建指南
数据库·redis·缓存
旺仔来了2 小时前
不联网的Linux下部署python环境
linux·开发语言·python
小江的记录本3 小时前
【JVM虚拟机】垃圾回收GC:垃圾回收算法:标记-清除、标记-复制、标记-整理、分代收集(附《思维导图》+《面试高频考点清单》)
java·jvm·后端·python·算法·安全·面试
IP搭子来一个3 小时前
爬虫采集大量返回 403、429,到底卡在哪一环?
网络·爬虫·python