[Zope3-checkins] SVN: Zope3/trunk/src/zope/cachedescriptors/
Converted the tests to a doctest. Added lazy properties.
Jim Fulton
jim at zope.com
Thu Dec 16 16:48:54 EST 2004
Log message for revision 28640:
Converted the tests to a doctest. Added lazy properties.
Changed:
U Zope3/trunk/src/zope/cachedescriptors/README.txt
U Zope3/trunk/src/zope/cachedescriptors/__init__.py
U Zope3/trunk/src/zope/cachedescriptors/property.py
A Zope3/trunk/src/zope/cachedescriptors/property.txt
D Zope3/trunk/src/zope/cachedescriptors/tests/
A Zope3/trunk/src/zope/cachedescriptors/tests.py
-=-
Modified: Zope3/trunk/src/zope/cachedescriptors/README.txt
===================================================================
--- Zope3/trunk/src/zope/cachedescriptors/README.txt 2004-12-16 21:48:49 UTC (rev 28639)
+++ Zope3/trunk/src/zope/cachedescriptors/README.txt 2004-12-16 21:48:54 UTC (rev 28640)
@@ -1 +1,24 @@
-See __init__.py.
+Cached descriptors
+
+Cached descriptors cache their output. They take into account
+instance attributes that they depend on, so when the instance
+attributes change, the descriptors will change the values they
+return.
+
+Cached descriptors cache their data in _v_ attributes, so they are
+also useful for managing the computation of volatile attributes for
+persistent objects.
+
+Persistent descriptors:
+
+ property
+
+ A simple computed property. See property.txt.
+
+ method
+
+ Idempotent method. The return values are cached based on method
+ arguments and on any instance attributes that the methods are
+ defined to depend on.
+
+ **Note**, methods haven't been implemented yet.
Modified: Zope3/trunk/src/zope/cachedescriptors/__init__.py
===================================================================
--- Zope3/trunk/src/zope/cachedescriptors/__init__.py 2004-12-16 21:48:49 UTC (rev 28639)
+++ Zope3/trunk/src/zope/cachedescriptors/__init__.py 2004-12-16 21:48:54 UTC (rev 28640)
@@ -1,40 +1 @@
-##############################################################################
#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Cached descriptors
-
-Cached descriptors cache their output. They take into account
-instance attributes that they depend on, so when the instance
-attributes change, the descriptors will change the values they
-return.
-
-Cached descriptors cache their data in _v_ attributes, so they are
-also useful for managing the computation of volatile attributes for
-persistent objects.
-
-Persistent descriptors:
-
- property
-
- A simple computed property
-
- method
-
- Idempotent method. The return values are cached based on method
- arguments and on any instance attributes that the methods are
- defined to depend on.
-
- **Note**, methods haven't been implemented yet.
-
-$Id$
-"""
Modified: Zope3/trunk/src/zope/cachedescriptors/property.py
===================================================================
--- Zope3/trunk/src/zope/cachedescriptors/property.py 2004-12-16 21:48:49 UTC (rev 28639)
+++ Zope3/trunk/src/zope/cachedescriptors/property.py 2004-12-16 21:48:54 UTC (rev 28640)
@@ -19,35 +19,6 @@
class CachedProperty(object):
"""Cached Properties
-
- Cached properties are computed properties that cache their computed
- values. They take into account instance attributes that they depend
- on, so when the instance attributes change, the properties will change
- the values they return.
-
- Cached properties cache their data in _v_ attributes, so they are
- also useful for managing the computation of volatile attributes for
- persistent objects.
-
- Example::
-
- from persistent import Persistent
- from zope.cachedescriptors.property import CachedProperty
-
- class FileManager(Persistent):
-
- def __init__(self, filename):
- self.filename = filename
-
- def file(self):
- return open(self.filename)
-
- file = CachedProperty(file, 'filename')
-
- file_manager = FileManager('data.txt')
-
- x = file_manager.file.read(10)
-
"""
def __init__(self, func, *names):
@@ -79,3 +50,23 @@
setattr(inst, value_name, value)
return value
+
+
+class Lazy(object):
+ """Lazy Attributes
+ """
+
+ def __init__(self, func, name=None):
+ if name is None:
+ name = func.__name__
+ self.data = (func, name)
+
+ def __get__(self, inst, class_):
+ if inst is None:
+ return self
+
+ func, name = self.data
+ value = func(inst)
+ inst.__dict__[name] = value
+
+ return value
Copied: Zope3/trunk/src/zope/cachedescriptors/property.txt (from rev 28622, Zope3/trunk/src/zope/cachedescriptors/property.py)
===================================================================
--- Zope3/trunk/src/zope/cachedescriptors/property.py 2004-12-10 19:58:18 UTC (rev 28622)
+++ Zope3/trunk/src/zope/cachedescriptors/property.txt 2004-12-16 21:48:54 UTC (rev 28640)
@@ -0,0 +1,128 @@
+Cached Properties
+=================
+
+Cached properties are computed properties that cache their computed
+values. They take into account instance attributes that they depend
+on, so when the instance attributes change, the properties will change
+the values they return.
+
+Cached properties cache their data in _v_ attributes, so they are
+also useful for managing the computation of volatile attributes for
+persistent objects. Let's look at an example:
+
+ >>> from zope.cachedescriptors import property
+ >>> import math
+
+ >>> 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)
+
+If we ask for the radius the first time:
+
+ >>> '%.2f' % point.radius
+ computing radius
+ '2.24'
+
+We see that the radius function is called, but if we ask for it again:
+
+ >>> '%.2f' % point.radius
+ '2.24'
+
+The function isn't called. If we change one of the attribute the
+radius depends on, it will be recomputed:
+
+ >>> point.x = 2.0
+ >>> '%.2f' % point.radius
+ computing radius
+ '2.83'
+
+But changing other attributes doesn't cause recomputation:
+
+ >>> point.q = 1
+ >>> '%.2f' % point.radius
+ '2.83'
+
+Note that we don't have any non-volitile attributes added:
+
+ >>> names = [name for name in point.__dict__ if not name.startswith('_v_')]
+ >>> names.sort()
+ >>> names
+ ['q', 'x', 'y']
+
+Lazy Computed Attributes
+------------------------
+
+The `property` module provides another descriptor that supports a
+slightly different caching model: lazy attributes. Like cached
+proprties, they are computed the first time they are used. however,
+they aren't stored in volatile attributes and they aren't
+automatically updated when other attributes change. Furthermore, the
+store their data using their attribute name, thus overriding
+themselves. This provides much faster attribute access after the
+attribute has been computed. Let's look at the previous example using
+lazy attributes:
+
+ >>> 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.Lazy(radius)
+
+ >>> point = Point(1.0, 2.0)
+
+If we ask for the radius the first time:
+
+ >>> '%.2f' % point.radius
+ computing radius
+ '2.24'
+
+We see that the radius function is called, but if we ask for it again:
+
+ >>> '%.2f' % point.radius
+ '2.24'
+
+The function isn't called. If we change one of the attribute the
+radius depends on, it still isn't called:
+
+ >>> point.x = 2.0
+ >>> '%.2f' % point.radius
+ '2.24'
+
+If we want the radius to be recomputed, we have to manually delete it:
+
+ >>> del point.radius
+
+ >>> point.x = 2.0
+ >>> '%.2f' % point.radius
+ computing radius
+ '2.83'
+
+Note that the radius is stored in the instance dictionary:
+
+ >>> '%.2f' % point.__dict__['radius']
+ '2.83'
+
+The lazy attribute needs to know the attribute name. It normally
+deduces the attribute name from the name of the function passed. If we
+want to use a different name, we need to pass it:
+
+ >>> def d(point):
+ ... print 'computing diameter'
+ ... return 2*point.radius
+
+ >>> Point.diameter = property.Lazy(d, 'diameter')
+ >>> '%.2f' % point.diameter
+ computing diameter
+ '5.66'
Added: Zope3/trunk/src/zope/cachedescriptors/tests.py
===================================================================
--- Zope3/trunk/src/zope/cachedescriptors/tests.py 2004-12-16 21:48:49 UTC (rev 28639)
+++ Zope3/trunk/src/zope/cachedescriptors/tests.py 2004-12-16 21:48:54 UTC (rev 28640)
@@ -0,0 +1,27 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test hookup
+
+$Id$
+"""
+import unittest
+
+def test_suite():
+ from zope.testing import doctest
+ return doctest.DocFileSuite('property.txt')
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
+
+
More information about the Zope3-Checkins
mailing list