跳转到主要内容

Python和Zope的缓存描述符

项目描述

gocept.cache

方法缓存

带超时的缓存

带超时的缓存缓存具有特定超时时间的方法

>>> import math
>>> import gocept.cache.method
>>>
>>> class Point(object):
...
...     def __init__(self, x, y):
...         self.x, self.y = x, y
...
...     @gocept.cache.method.Memoize(0.1)
...     def distance(self, x, y):
...         print('computing distance')
...         return math.sqrt((self.x - x)**2 + (self.y - y)**2)
...
...     @gocept.cache.method.Memoize(0.1, ignore_self=True)
...     def add_one(self, i):
...         if not isinstance(i, int):
...             print("I want an int")
...         else:
...             print('adding one')
...             return i + 1
...
>>> point = Point(1.0, 2.0)

当我们第一次请求距离时,它会进行计算

>>> point.distance(2, 2)
computing distance
1.0

第二次距离不会计算,而是从缓存中返回

>>> point.distance(2, 2)
1.0

现在,让我们等待0.1秒,这是我们设置的缓存超时值。之后,再次计算距离。

>>> import time
>>> time.sleep(0.5)
>>> point.distance(2, 2)
computing distance
1.0

当我们创建一个新的实例时,新实例将获得自己的缓存。

>>> p2 = Point(1.0, 2.0)
>>> p2.distance(2, 2)
computing distance
1.0

也可以显式忽略自身。我们为< cite>add_one方法做了这件事。

>>> point.add_one(3)
adding one
4

第二次计算的结果并不如您所预期:>> point.add_one(3) 4

如果我们现在询问< cite>p2,结果也不会进行计算。

>>> p2.add_one(3)
4

如果我们将不可哈希的参数放入缓存函数中,它将不会被缓存。

>>> point.add_one({'a': 1})
I want an int
>>> point.add_one({'a': 1})
I want an int

装饰的方法可以被检查,并产生与原始相同的输出。

>>> from inspect import signature
>>> Point.distance.__name__
'distance'
>>> tuple(signature(Point.distance).parameters.keys())
('self', 'x', 'y')

显式排除特定值的缓存

尤其是当与外部系统交互时,您希望处理错误(例如,通过返回一个空结果)。但通常您不希望缓存这个特殊的返回值。

这是我们的数据库。

>>> class DB(object):
...
...     call_count = 0
...
...     def get_country(self, zip):
...         self.call_count += 1
...         if self.call_count % 2 == 0:
...             raise ValueError('Some strange response')
...         return 'Somecountry'
...

它将在每两次调用中抛出一个异常。

>>> db = DB()
>>> db.get_country(12345)
'Somecountry'
>>> db.get_country(12345)
Traceback (most recent call last):
...
ValueError: Some strange response
>>> db.get_country(12345)
'Somecountry'
>>> db.get_country(12345)
Traceback (most recent call last):
...
ValueError: Some strange response

现在我们使用do_not_cache_and_return来指定,如果发生错误,我们不希望缓存。

>>> import gocept.cache.method
>>>
>>> class Country(object):
...
...     db = DB()
...
...     @gocept.cache.method.Memoize(1000)
...     def by_zip(self, zip):
...         try:
...             return self.db.get_country(zip)
...         except ValueError:
...             return gocept.cache.method.do_not_cache_and_return(
...                     'DB is down.')
...
>>> country = Country()

第一次调用将得到缓存,因此我们每次调用都能得到正确的国家。

>>> country.by_zip(12345)
'Somecountry'
>>> country.by_zip(12345)
'Somecountry'
>>> country.by_zip(12345)
'Somecountry'

使用新的zip,第二次调用get_country方法,将抛出一个异常,这个异常不会被缓存。

>>> country.by_zip(54321)
'DB is down.'

再次调用它将调用get_country,因为特殊的返回值没有被缓存。

>>> country.by_zip(54321)
'Somecountry'

现在我们总是得到缓存的值。

>>> country.by_zip(54321)
'Somecountry'

将缓存存储在属性上

如果您想更控制gocept.cache.method.Memoize使用的缓存(例如,您想将其与gocept.cache.property.CacheDataManager关联以在事务边界上使它失效),您可以使用@memoize_on_attribute装饰器从实例检索缓存字典。

>>> class Bar(object):
...     cache = {}
...
...     @gocept.cache.method.memoize_on_attribute('cache', 10)
...     def echo(self, x):
...         print('miss')
...         return x
>>> bar = Bar()
>>> bar.echo(5)
miss
5
>>> bar.echo(5)
5
>>> bar.cache.clear()
>>> bar.echo(5)
miss
5

这个装饰器应该用在方法上,而不是用在普通函数上,因为它必须能够从函数的第一个参数(对于方法是self)检索缓存字典。

>>> @gocept.cache.method.memoize_on_attribute('cache', 10)
... def bar():
...     print('foo')
>>> bar()
Traceback (most recent call last):
TypeError: gocept.cache.method.memoize_on_attribute could not retrieve cache attribute 'cache' for function <function bar at 0x...>
>>> @gocept.cache.method.memoize_on_attribute('cache', 10)
... def baz(x):
...     print('foo')
>>> baz(5)
Traceback (most recent call last):
TypeError: gocept.cache.method.memoize_on_attribute could not retrieve cache attribute 'cache' for function <function baz at 0x...>

缓存的属性

事务边界缓存

事务边界缓存在事务边界上失效。

创建一个类并设置一些数据

>>> import gocept.cache.property
>>> class Foo(object):
...
...     cache = gocept.cache.property.TransactionBoundCache('_v_cache', dict)
...

(注意:您可能想为缓存存储使用一个“易挥发”的属性名,否则只读访问缓存会触发写入。)

>>> foo = Foo()
>>> foo.cache
{}
>>> foo.cache['A'] = 1
>>> foo.cache
{'A': 1}

如果我们提交事务,缓存将再次为空。

>>> import transaction
>>> transaction.commit()
>>> foo.cache
{}

在回滚时也会发生同样的情况。

>>> foo.cache['A'] = 1
>>> foo.cache
{'A': 1}
>>> transaction.abort()
>>> foo.cache
{}

变更

5.0 (2021-08-31)

向后不兼容的变更

  • 将许可证从ZPL更改为MIT。

  • 停止支持Python 2.7和3.6。

功能

  • 添加对Python 3.10的支持。

其他变更

  • 使用Github actions作为CI。

4.0 (2020-02-17)

  • 添加对Python 3.7,3.8和3.9a3的支持。

  • 停止支持Python 3.4和3.5。

  • 迁移到github。

3.1 (2018-11-20)

  • 添加对Python 3.7的支持。

  • 删除有关inspect的弃用警告。

3.0 (2017-11-20)

  • 在setup.py中删除对< span class="docutils literal">__file__的使用,以适应最近的setuptools。

  • 添加对Python 3.6的支持。

  • 停止支持Python 3.3。

2.1 (2016-11-17)

  • 错误修复:.property.CacheDataManager不再在tpc_vote()和commit()中使缓存失效,而是在tpc_finish()中使缓存失效。

  • 如果在.property.TransactionBoundCache中事务连接失败,则引发TransactionJoinError。

2.0 (2016-03-18)

  • 停止支持Python 2.6。

  • 声明支持PyPy和PyPy3。

1.0 (2015-09-25)

  • 现在测试对当前依赖项的最新版本。

  • 停止支持Python 3.2。

  • 声明支持Python 3.4和3.5。

0.6.1 (2013-09-13)

  • 完成Python 3兼容性

0.6 (2013-09-13)

  • 更改未记录,抱歉。

0.6b2 (2013-09-05)

  • 更改未记录,抱歉。

0.6b1 (2013-09-05)

  • Python3兼容性

0.5.2 (2012-06-22)

  • 在memoized方法/函数中添加了gocept.cache.method.do_not_cache_and_return(value),它将返回给定的值,而不对其进行缓存。

0.5.1 (2012-03-10)

  • 防止由于在Memoize调用期间调用collect(在多线程环境中)而导致gocept.cache.method.Memoize的值未存储的竞争条件。

  • 将测试版本锁定在ZTK 1.1。

0.5 (2011-03-15)

  • 用transaction替换对ZODB的依赖。

0.4 (2009-06-18)

  • 使用zope.testing.cleanup注册清除缓存。

0.3 (2008-12-19)

  • 添加@memoize_on_attribute,从实例检索缓存而不是使用gocept.cache.method的内置缓存。

0.2.2 (2007-12-17)

  • 修复了在 TransactionBoundCache 中的错误,在事务中止时缓存未失效。

0.2.1 (2007-10-17)

  • 修复了 TransactionBoundCache 中的一个错误,导致日志中出现了错误:TypeError: <lambda>() takes exactly 1 argument (2 given)

项目详情


下载文件

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

源分发

gocept.cache-5.0.tar.gz (13.0 kB 查看哈希值)

上传时间

构建分发

gocept.cache-5.0-py3-none-any.whl (12.5 kB 查看哈希值)

上传时间 Python 3

支持者