[Zope-Checkins] SVN: Zope/branches/2.13/ fix `LazyMap` to avoid unnecessary function calls when not accessing items in order (fixes http://dev.plone.org/plone/ticket/9018)

Andreas Zeidler az at zitc.de
Tue Dec 14 09:12:11 EST 2010


Log message for revision 118863:
  fix `LazyMap` to avoid unnecessary function calls when not accessing items in order (fixes http://dev.plone.org/plone/ticket/9018)
  

Changed:
  U   Zope/branches/2.13/doc/CHANGES.rst
  U   Zope/branches/2.13/src/Products/ZCatalog/Lazy.py
  U   Zope/branches/2.13/src/Products/ZCatalog/tests/test_lazy.py

-=-
Modified: Zope/branches/2.13/doc/CHANGES.rst
===================================================================
--- Zope/branches/2.13/doc/CHANGES.rst	2010-12-14 13:24:24 UTC (rev 118862)
+++ Zope/branches/2.13/doc/CHANGES.rst	2010-12-14 14:12:11 UTC (rev 118863)
@@ -11,6 +11,8 @@
 Bugs Fixed
 ++++++++++
 
+- Fix `LazyMap` to avoid unnecessary function calls.
+
 - LP 686664: WebDAV Lock Manager ZMI view wasn't accessible.
 
 2.13.1 (2010-12-07)

Modified: Zope/branches/2.13/src/Products/ZCatalog/Lazy.py
===================================================================
--- Zope/branches/2.13/src/Products/ZCatalog/Lazy.py	2010-12-14 13:24:24 UTC (rev 118862)
+++ Zope/branches/2.13/src/Products/ZCatalog/Lazy.py	2010-12-14 14:12:11 UTC (rev 118863)
@@ -145,44 +145,28 @@
     # Don't access data until necessary
 
     def __init__(self, func, seq, length=None):
-        self._seq = seq
-        self._data = []
-        self._func = func
+        self._seq=seq
+        self._func=func
         if length is not None:
-            self._len = length
+            self._len=length
         else:
             self._len = len(seq)
+        self._marker = object()
+        self._data = [self._marker] * self._len
 
-    def __getitem__(self, index):
-        data = self._data
+    def __getitem__(self,index):
+        data=self._data
         try:
-            s = self._seq
+            s=self._seq
         except AttributeError:
             return data[index]
 
-        i = index
-        if i < 0:
-            i = len(self) + i
-        if i < 0:
-            raise IndexError(index)
+        value = data[index]
+        if value is self._marker:
+            value = data[index] = self._func(s[index])
+        return value
 
-        ind = len(data)
-        if i < ind:
-            return data[i]
-        ind = ind - 1
 
-        func = self._func
-        while i > ind:
-            try:
-                ind = ind + 1
-                data.append(func(s[ind]))
-            except IndexError:
-                del self._func
-                del self._seq
-                raise IndexError(index)
-        return data[i]
-
-
 class LazyFilter(Lazy):
     # Act like a sequence, but get data from a filtering process.
     # Don't access data until necessary. Only data for which test(data)

Modified: Zope/branches/2.13/src/Products/ZCatalog/tests/test_lazy.py
===================================================================
--- Zope/branches/2.13/src/Products/ZCatalog/tests/test_lazy.py	2010-12-14 13:24:24 UTC (rev 118862)
+++ Zope/branches/2.13/src/Products/ZCatalog/tests/test_lazy.py	2010-12-14 14:12:11 UTC (rev 118863)
@@ -113,7 +113,17 @@
         lmap = self._createLMap(filter, seq1, seq2, seq3)
         self._compare(lmap, [str(x).lower() for x in (seq1 + seq2 + seq3)])
 
+    def testMapFuncIsOnlyCalledAsNecessary(self):
+        seq = range(10)
+        count = [0]     # closure only works with list, and `nonlocal` in py3
+        def func(x):
+            count[0] += 1
+            return x
+        lmap = self._createLMap(func, seq)
+        self.assertEqual(lmap[5], 5)
+        self.assertEqual(count[0], 1)
 
+
 class TestLazyFilter(TestLazyCat):
 
     def _createLSeq(self, *seq):



More information about the Zope-Checkins mailing list