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 cite>方法做了这件事。
>>> point.add_one(3) adding one 4
第二次计算的结果并不如您所预期:>> point.add_one(3) 4
如果我们现在询问< cite>p2 cite>,结果也不会进行计算。
>>> 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__ span>的使用,以适应最近的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 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | c3cd08321fe74f33f8cfbbb515b975e209167566e1f7d2085416c63079702c42 |
|
MD5 | 694e56cbd124b0af56289054591cacb5 |
|
BLAKE2b-256 | ede4892ba50ee1deb5480a6fb85819f3e17222248f73d3d2fc6a546fc24da58b |
gocept.cache-5.0-py3-none-any.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 6409d63a5f243d8984dc7de621a3c57902ade2a99bf5252cdd21823334c14e5b |
|
MD5 | 0c95bb78d1eb7e7b647451fde0b33398 |
|
BLAKE2b-256 | a62c971af0bb6c06236245d2d2199bb36be9c559af2bef6844bf6467703540e1 |