方法和属性缓存装饰器
项目描述
zope.cachedescriptors
缓存描述符缓存其输出。它们考虑了它们依赖的实例属性,因此当实例属性更改时,描述符将更改它们返回的值。
缓存描述符将数据缓存在_v_属性中,因此它们也用于管理持久对象的易变属性的计算。
持久描述符
property
一个简单的计算属性。
见 src/zope/cachedescriptors/property.rst.
method
幂等方法。返回值基于方法参数以及方法定义中指定的任何实例属性。
见 src/zope/cachedescriptors/method.rst.
缓存属性
缓存属性是计算属性,它们缓存其计算值。它们考虑了它们依赖的实例属性,因此当实例属性更改时,属性将更改它们返回的值。
CachedProperty
缓存属性将数据缓存在_v_属性中,因此它们也用于管理持久对象的易变属性的计算。以下是一个例子
>>> from zope.cachedescriptors import property >>> import math>>> class Point: ... ... def __init__(self, x, y): ... self.x, self.y = x, y ... ... @property.CachedProperty('x', 'y') ... def radius(self): ... print('computing radius') ... return math.sqrt(self.x**2 + self.y**2)>>> point = Point(1.0, 2.0)
如果第一次请求半径
>>> '%.2f' % point.radius computing radius '2.24'
我们看到半径函数被调用,但如果再次请求它
>>> '%.2f' % point.radius '2.24'
函数不会被调用。如果我们更改半径依赖的一个属性,它将被重新计算
>>> point.x = 2.0 >>> '%.2f' % point.radius computing radius '2.83'
但更改其他属性不会引起重新计算
>>> point.q = 1 >>> '%.2f' % point.radius '2.83'
注意我们没有添加任何非易失性属性
>>> names = [name for name in point.__dict__ if not name.startswith('_v_')] >>> names.sort() >>> names ['q', 'x', 'y']
为了向后兼容,同样的内容也可以使用装饰器语法来交替编写
>>> class Point: ... ... def __init__(self, x, y): ... self.x, self.y = x, y ... ... def radius(self): ... print('computing radius') ... return math.sqrt(self.x**2 + self.y**2) ... radius = property.CachedProperty(radius, 'x', 'y')>>> point = Point(1.0, 2.0)
如果第一次请求半径
>>> '%.2f' % point.radius computing radius '2.24'
我们看到半径函数被调用,但如果再次请求它
>>> '%.2f' % point.radius '2.24'
函数不会被调用。如果我们更改半径依赖的一个属性,它将被重新计算
>>> point.x = 2.0 >>> '%.2f' % point.radius computing radius '2.83'
如果通过类访问属性,则保留文档和__name__。这允许Sphinx提取文档。
>>> class Point: ... ... def __init__(self, x, y): ... self.x, self.y = x, y ... ... @property.CachedProperty('x', 'y') ... def radius(self): ... '''The length of the line between self.x and self.y''' ... print('computing radius') ... return math.sqrt(self.x**2 + self.y**2)>>> print(Point.radius.__doc__) The length of the line between self.x and self.y >>> print(Point.radius.__name__) radius
可以指定一个没有依赖关系的CachedProperty。为了向后兼容,这可以以几种不同的方式编写
>>> class Point: ... def __init__(self, x, y): ... self.x, self.y = x, y ... ... @property.CachedProperty ... def no_deps_no_parens(self): ... print("No deps, no parens") ... return 1 ... ... @property.CachedProperty() ... def no_deps(self): ... print("No deps") ... return 2 ... ... def no_deps_old_style(self): ... print("No deps, old style") ... return 3 ... no_deps_old_style = property.CachedProperty(no_deps_old_style) >>> point = Point(1.0, 2.0) >>> point.no_deps_no_parens No deps, no parens 1 >>> point.no_deps_no_parens 1 >>> point.no_deps No deps 2 >>> point.no_deps 2 >>> point.no_deps_old_style No deps, old style 3 >>> point.no_deps_old_style 3
延迟计算的属性
property模块提供了另一个支持略有不同缓存模型的描述符:延迟属性。像缓存的属性一样,它们在第一次使用时进行计算。然而,它们不存储在易失性属性中,也不会在其他属性更改时自动更新。此外,它们使用它们的属性名存储数据,从而覆盖了自己。这为计算后的属性提供了更快的属性访问。让我们看看使用延迟属性的先前列表
>>> class Point: ... ... def __init__(self, x, y): ... self.x, self.y = x, y ... ... @property.Lazy ... def radius(self): ... print('computing radius') ... return math.sqrt(self.x**2 + self.y**2)>>> point = Point(1.0, 2.0)
如果第一次请求半径
>>> '%.2f' % point.radius computing radius '2.24'
我们看到半径函数被调用,但如果再次请求它
>>> '%.2f' % point.radius '2.24'
函数不会被调用。如果我们更改半径依赖的属性之一,它仍然不会被调用
>>> point.x = 2.0 >>> '%.2f' % point.radius '2.24'
如果我们想重新计算半径,我们必须手动删除它
>>> del point.radius>>> point.x = 2.0 >>> '%.2f' % point.radius computing radius '2.83'
注意半径存储在实例字典中
>>> '%.2f' % point.__dict__['radius'] '2.83'
延迟属性需要知道属性名。它通常从传递给函数的名称推断属性名。如果我们想使用不同的名称,我们需要传递它
>>> def d(point): ... print('computing diameter') ... return 2*point.radius>>> Point.diameter = property.Lazy(d, 'diameter') >>> '%.2f' % point.diameter computing diameter '5.66'
如果通过类访问属性,则保留文档和__name__。这允许Sphinx提取文档。
>>> class Point: ... ... def __init__(self, x, y): ... self.x, self.y = x, y ... ... @property.Lazy ... def radius(self): ... '''The length of the line between self.x and self.y''' ... print('computing radius') ... return math.sqrt(self.x**2 + self.y**2)>>> print(Point.radius.__doc__) The length of the line between self.x and self.y >>> print(Point.radius.__name__) radius
通过实例访问属性时,属性的文档将与返回值相同
>>> p = Point(1.0, 2.0) >>> p.radius.__doc__ == float.__doc__ computing radius True
这与标准Python property装饰器具有相同的行为。
readproperty
readproperty类似于延迟计算的属性,除了属性不是由属性设置的
>>> class Point: ... ... def __init__(self, x, y): ... self.x, self.y = x, y ... ... @property.readproperty ... def radius(self): ... print('computing radius') ... return math.sqrt(self.x**2 + self.y**2)>>> point = Point(1.0, 2.0)>>> '%.2f' % point.radius computing radius '2.24'>>> '%.2f' % point.radius computing radius '2.24'
但是,你可以通过设置值来替换属性。这是与内置的property的主要区别
>>> point.radius = 5 >>> point.radius 5
如果通过类访问属性,则保留文档和__name__。这允许Sphinx提取文档。
>>> class Point: ... ... def __init__(self, x, y): ... self.x, self.y = x, y ... ... @property.readproperty ... def radius(self): ... '''The length of the line between self.x and self.y''' ... print('computing radius') ... return math.sqrt(self.x**2 + self.y**2)>>> print(Point.radius.__doc__) The length of the line between self.x and self.y >>> print(Point.radius.__name__) radius
cachedIn
cachedIn属性允许指定存储计算值的属性
>>> class Point: ... ... def __init__(self, x, y): ... self.x, self.y = x, y ... ... @property.cachedIn('_radius_attribute') ... def radius(self): ... print('computing radius') ... return math.sqrt(self.x**2 + self.y**2)>>> point = Point(1.0, 2.0)>>> '%.2f' % point.radius computing radius '2.24'>>> '%.2f' % point.radius '2.24'
半径缓存在给定名称的属性中,在本例中是_radius_attribute
>>> '%.2f' % point._radius_attribute '2.24'
当删除属性时,半径将重新计算一次。这允许无效化
>>> del point._radius_attribute>>> '%.2f' % point.radius computing radius '2.24'>>> '%.2f' % point.radius '2.24'
如果通过类访问属性,则保留文档。这允许Sphinx提取文档。
>>> class Point: ... ... def __init__(self, x, y): ... self.x, self.y = x, y ... ... @property.cachedIn('_radius_attribute') ... def radius(self): ... '''The length of the line between self.x and self.y''' ... print('computing radius') ... return math.sqrt(self.x**2 + self.y**2)>>> print(Point.radius.__doc__) The length of the line between self.x and self.y
方法缓存
cachedIn
cachedIn属性允许指定存储计算值的属性
>>> import math >>> from zope.cachedescriptors import method>>> class Point(object): ... ... def __init__(self, x, y): ... self.x, self.y = x, y ... ... @method.cachedIn('_cache') ... def distance(self, x, y): ... """Compute the distance""" ... print('computing distance') ... return math.hypot(self.x - x, self.y - y) ... >>> point = Point(1.0, 2.0)
值只计算一次
>>> point.distance(2, 2) computing distance 1.0 >>> point.distance(2, 2) 1.0
使用不同的参数计算新的距离
>>> point.distance(5, 2) computing distance 4.0 >>> point.distance(5, 2) 4.0
数据存储在给定的_cache属性中
>>> isinstance(point._cache, dict) True>>> sorted(point._cache.items()) [(((2, 2), ()), 1.0), (((5, 2), ()), 4.0)]
可以显式使数据无效
>>> point.distance.invalidate(point, 5, 2) >>> point.distance(5, 2) computing distance 4.0
使不在缓存中的键无效不会导致错误
>>> point.distance.invalidate(point, 47, 11)
函数的文档被保留(无论是通过实例还是类),允许Sphinx提取它
>>> print(point.distance.__doc__) Compute the distance >>> print(point.distance.__name__) distance >>> print(Point.distance.__doc__) Compute the distance >>> print(Point.distance.__name__) distance
可以传递一个用于缓存属性的工厂。创建另一个Point类
>>> class MyDict(dict): ... pass >>> class Point(object): ... ... def __init__(self, x, y): ... self.x, self.y = x, y ... ... @method.cachedIn('_cache', MyDict) ... def distance(self, x, y): ... print('computing distance') ... return math.sqrt((self.x - x)**2 + (self.y - y)**2) ... >>> point = Point(1.0, 2.0) >>> point.distance(2, 2) computing distance 1.0
现在缓存是MyDict实例
>>> isinstance(point._cache, MyDict) True
更改
5.0 (2023-03-27)
添加对Python 3.11的支持。
停止支持Python 2.7、3.5、3.6。
4.4 (2022-09-07)
停止支持Python 3.4。
添加对Python 3.7、3.8、3.9、3.10的支持。
4.3.1 (2017-12-09)
修复将在即将发布的Python 3.7版本中中断的测试。
4.3.0 (2017-07-27)
添加对Python 3.6的支持。
停止支持Python 3.3。
4.2.0 (2016-09-05)
添加对Python 3.5的支持。
停止支持Python 2.6和3.2。
从 property 模块中获取的所有属性都保留了底层函数的文档字符串,除了 cachedIn,其余都保留了 functools.update_wrapper 保留的所有内容。
property.CachedProperty 可用作装饰器,带或不带依赖属性名称。
method.cachedIn 保留了底层函数的文档字符串,以及 functools.wraps 保留的所有内容。
4.1.0 (2014-12-26)
添加对 PyPy 和 PyPy3 的支持。
添加对 Python 3.4 的支持。
添加对 Travis 上的测试支持。
4.0.0 (2013-02-13)
放弃对 Python 2.4 和 2.5 的支持。
添加对 Python 3.2 和 3.3 的支持。
3.5.1 (2010-04-30)
删除对 zope.testing 的未声明测试依赖。
3.5.0 (2009-02-10)
通过允许指定 zope.cachedescriptors.method.cachedIn 的存储工厂(默认为 dict)来删除对 ZODB 的依赖。如果您需要使用 BTree,必须将其作为 factory 参数传递给 zope.cachedescriptors.method.cachedIn 装饰器。
删除与 zpkg 相关的文件。
对包描述和文档进行一些清理。
将包邮件列表地址更改为 zope-dev@zope.org,因为 zope3-dev@zope.org 现已停用。
3.4.0 (2007-08-30)
作为独立包的首次发布。
项目详情
下载文件
下载适合您平台的应用程序文件。如果您不确定选择哪个,请了解有关 安装包 的更多信息。