跳转到主要内容

类属性缓存装饰器(从cached-property分支而来)。

项目描述

https://img.shields.io/travis/althonos/property-cached/master.svg?style=flat-square https://img.shields.io/codecov/c/gh/althonos/property-cached.svg?style=flat-square https://img.shields.io/pypi/v/property-cached.svg?style=flat-square https://img.shields.io/badge/code%20style-black-000000.svg?style=flat-square

类属性缓存装饰器(从cached-property分支而来)。

由于上游库的维护者似乎不再维护它,因此从该库分支了这个库。它可以作为完全兼容API的替代品(在代码中用property_cached代替cached_property,效果立竿见影)。如果原库的开发重新开始,这个库可能会被弃用。

以下包含稍作修改的README

为什么?

  • 使缓存耗时或计算成本高的属性变得快速且简单。

  • 因为我厌倦了从非Web项目复制粘贴这段代码到非Web项目中。

如何使用它

让我们定义一个具有成本高昂的属性的类。每次你停留在这里,价格都会上涨50美元!

class Monopoly(object):

    def __init__(self):
        self.boardwalk_price = 500

    @property
    def boardwalk(self):
        # In reality, this might represent a database call or time
        # intensive task like calling a third-party API.
        self.boardwalk_price += 50
        return self.boardwalk_price

现在运行它

>>> monopoly = Monopoly()
>>> monopoly.boardwalk
550
>>> monopoly.boardwalk
600

现在让我们将boardwalk属性转换为cached_property

from cached_property import cached_property

class Monopoly(object):

    def __init__(self):
        self.boardwalk_price = 500

    @cached_property
    def boardwalk(self):
        # Again, this is a silly example. Don't worry about it, this is
        #   just an example for clarity.
        self.boardwalk_price += 50
        return self.boardwalk_price

现在当我们运行它时,价格保持在550美元。

>>> monopoly = Monopoly()
>>> monopoly.boardwalk
550
>>> monopoly.boardwalk
550
>>> monopoly.boardwalk
550

为什么monopoly.boardwalk的值没有改变?因为它是一个缓存属性

清除缓存

缓存的函数结果可能会被外部力量失效。让我们演示如何强制缓存失效

>>> monopoly = Monopoly()
>>> monopoly.boardwalk
550
>>> monopoly.boardwalk
550
>>> # invalidate the cache
>>> del monopoly.__dict__['boardwalk']
>>> # request the boardwalk property again
>>> monopoly.boardwalk
600
>>> monopoly.boardwalk
600

与线程协同工作

如果很多人同时想留在Boardwalk,怎么办?这意味着使用线程,不幸的是,这会与标准cached_property产生问题。在这种情况下,切换到使用threaded_cached_property

from cached_property import threaded_cached_property

class Monopoly(object):

    def __init__(self):
        self.boardwalk_price = 500

    @threaded_cached_property
    def boardwalk(self):
        """threaded_cached_property is really nice for when no one waits
            for other people to finish their turn and rudely start rolling
            dice and moving their pieces."""

        sleep(1)
        self.boardwalk_price += 50
        return self.boardwalk_price

现在使用它

>>> from threading import Thread
>>> from monopoly import Monopoly
>>> monopoly = Monopoly()
>>> threads = []
>>> for x in range(10):
>>>     thread = Thread(target=lambda: monopoly.boardwalk)
>>>     thread.start()
>>>     threads.append(thread)

>>> for thread in threads:
>>>     thread.join()

>>> self.assertEqual(m.boardwalk, 550)

与async/await协同工作(Python 3.5+)

缓存的属性可以是异步的,在这种情况下,您必须像往常一样使用await来获取值。由于缓存,值只计算一次然后缓存

from cached_property import cached_property

class Monopoly(object):

    def __init__(self):
        self.boardwalk_price = 500

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

现在使用它

>>> async def print_boardwalk():
...     monopoly = Monopoly()
...     print(await monopoly.boardwalk)
...     print(await monopoly.boardwalk)
...     print(await monopoly.boardwalk)
>>> import asyncio
>>> asyncio.get_event_loop().run_until_complete(print_boardwalk())
550
550
550

请注意,这也与线程不兼容,大多数asyncio对象都不是线程安全的。如果您在每个线程中运行单独的事件循环,缓存的版本很可能会有错误的事件循环。总结一下,要么使用协作式多任务处理(事件循环),要么使用线程,但不要同时使用两者。

缓存超时

有时您希望物品的价格在一段时间后重置。使用cached_propertythreaded_cached_propertyttl版本。

import random
from cached_property import cached_property_with_ttl

class Monopoly(object):

    @cached_property_with_ttl(ttl=5) # cache invalidates after 5 seconds
    def dice(self):
        # I dare the reader to implement a game using this method of 'rolling dice'.
        return random.randint(2,12)

现在使用它

>>> monopoly = Monopoly()
>>> monopoly.dice
10
>>> monopoly.dice
10
>>> from time import sleep
>>> sleep(6) # Sleeps long enough to expire the cache
>>> monopoly.dice
3
>>> monopoly.dice
3

注意: ttl工具并不能可靠地清除缓存。这就是为什么它们被拆分成了单独的工具。请参阅https://github.com/pydanny/cached-property/issues/16

致谢

  • @pydanny,他为原始的cached-property实现做出了贡献。

  • Pip、Django、Werkzueg、Bottle、Pyramid和Zope,因为它们有自己的实现。这个包最初使用了一个与Bottle版本相匹配的实现。

  • Reinout Van Rees,他向我指出了cached_property装饰器。

  • @audreyr``_创建了``cookiecutter``_,这使得推出这个包只需@pydanny 15分钟。

  • @tinche指出线程问题并提供了解决方案。

  • @bcho提供了过期时间功能

历史记录

1.6.4 (2020-03-06)

  • 修复一些遗留的Python 2支持代码(#25

1.6.3 (2019-09-07)

  • 解决cached_property文档字符串不显示的问题(#171)。

1.6.2 (2019-07-22)

  • 修复元数据,以保留原始作者并添加@althonos作为维护者

1.6.1 (2019-07-22)

  • 修复了setup.cfg中存在的不必要依赖项

1.6.0 (2019-07-22)

  • 修复了类层次结构,cached_property现在继承自property

  • 支持槽类,并停止使用对象__dict__

  • 使用functools.update_wrapper改进函数包装

  • 实现自Python 3.6以来可用的__set_name__魔法方法

1.5.1 (2018-08-05)

  • 添加了对Python 3.7的正式支持

  • 移除了对Python 3.3的正式支持

1.4.3 (2018-06-14)

  • 从较旧版本的Python中捕获asyncio导入的SyntaxError,感谢@asottile

1.4.2 (2018-04-08)

  • 真正修复了测试,感谢@pydanny

1.4.1 (2018-04-08)

  • 将conftest.py添加到清单中,以便测试可以在tarball之外正常工作,感谢@dotlambda

  • 确保新的asyncio测试不会破坏Debian上Python 2.7的构建,感谢@pydanny

  • 通过black进行代码格式化,感谢@pydanny和@ambv

1.4.0 (2018-02-25)

  • 添加了asyncio支持,感谢@vbraun

  • 移除了Python 2.6支持,其生命周期的结束是5年前,感谢@pydanny

1.3.1 (2017-09-21)

  • 验证Python 3.6

1.3.0 (2015-11-24)

  • 从HISTORY.rst中删除了一些非ASCII字符,感谢@AdamWill

  • 添加了对Python 3.5的官方支持,感谢@pydanny和@audreyr

  • 移除了示例中放置不明确的锁,感谢@ionelmc

  • 修正了无效化缓存文档,感谢 @proofit404

  • 更新到最新的 Travis-CI 环境,感谢 @audreyr

1.2.0 (2015-04-28)

1.1.0 (2015-04-04)

  • 回归:由于缓存并非总是清除,我们已将过期时间特性分离到其自己的特定工具集中,感谢 @pydanny

  • 修复了 README 中的错别字,感谢 @zoidbergwill

1.0.0 (2015-02-13)

  • 将定时过期功能添加到 cached_property 装饰器中。

  • 向下不兼容:将 del monopoly.boardwalk 更改为 del monopoly['boardwalk'] 以支持新的 TTL 功能。

0.1.5 (2014-05-20)

  • 添加了新 threaded_cached_property 装饰器以支持多线程。

  • 文档化了缓存无效化

  • 更新了致谢

  • 获取了 bottle 实现的来源

0.1.4 (2014-05-17)

  • 修复了 py_modules 参数的问题。

0.1.3 (2014-05-17)

  • setup.py 中移除了包的导入。

0.1.2 (2014-05-17)

  • 文档修复。不为此打开 RTFD 实例,因为使用它非常简单。

0.1.1 (2014-05-17)

  • setup.py 修复。哎呀!

0.1.0 (2014-05-17)

  • PyPI 上的第一个版本。

项目详情


下载文件

下载适合您平台的项目文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。

源分布

property-cached-1.6.4.zip (23.5 kB 查看哈希值)

上传时间

构建分布

property_cached-1.6.4-py2.py3-none-any.whl (7.8 kB 查看哈希值)

上传时间 Python 2 Python 3

支持者

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面