1 """Module for the creation and use of iterator-based lazy lists.
2 this module defines a class LazyList which can be used to represent sequences
3 of values generated lazily. One can also create recursively defined lazy lists
4 that generate their values based on ones previously generated.
5
6 Backport to python 2.5 by Michael Pust
7 """
8
9 __author__ = 'Dan Spitz'
10 __all__ = ('LazyList', 'RecursiveLazyList', 'lazylist')
11
12 import itertools
15 """A Sequence whose values are computed lazily by an iterator.
16 """
18 self._exhausted = False
19 self._iterator = iter(iterable)
20 self._data = []
21
23 """Get the length of a LazyList's computed data."""
24 return len(self._data)
25
27 """Get an item from a LazyList.
28 i should be a positive integer or a slice object."""
29 if isinstance(i, int):
30
31
32 if i >= len(self):
33 self.exhaust(i)
34 elif i < 0:
35 raise ValueError('cannot index LazyList with negative number')
36 return self._data[i]
37
38
39 elif isinstance(i, slice):
40 start, stop, step = i.start, i.stop, i.step
41 if any(x is not None and x < 0 for x in (start, stop, step)):
42 raise ValueError('cannot index or step through a LazyList with'
43 'a negative number')
44
45 if start is None:
46 start = 0
47 if step is None:
48 step = 1
49
50 def LazyListIterator():
51 count = start
52 predicate = (stop is None) and (lambda: True) or (lambda: count < stop)
53 while predicate():
54 try:
55 yield self[count]
56
57
58 except IndexError:
59 break
60 count += step
61 return LazyListIterator()
62
63 raise TypeError('i must be an integer or slice')
64
66 """return an iterator over each value in the sequence,
67 whether it has been computed yet or not."""
68 return self[:]
69
71 """Return an iterator over the values in a LazyList that have
72 already been computed."""
73 return self[:len(self)]
74
76 """Exhaust the iterator generating this LazyList's values.
77 if index is None, this will exhaust the iterator completely.
78 Otherwise, it will iterate over the iterator until either the list
79 has a value for index or the iterator is exhausted.
80 """
81 if self._exhausted:
82 return
83 if index is None:
84 ind_range = itertools.count(len(self))
85 else:
86 ind_range = range(len(self), index + 1)
87
88 for ind in ind_range:
89 try:
90 self._data.append(self._iterator.next())
91 except StopIteration:
92 self._exhausted = True
93 break
94
96 - def __init__(self, prod, *args, **kwds):
98
100 return "<lastfm.lazylist>"
101
107
110 """Decorator for creating a RecursiveLazyList subclass.
111 This should decorate a generator function taking the LazyList object as its
112 first argument which yields the contents of the list in order.
113 """
114 return RecursiveLazyListFactory(gen)
115
116
117 if __name__ == '__main__':
118
119 @lazylist
121 yield 0
122 yield 1
123 for a, b in itertools.izip(lst, lst[1:]):
124 yield a + b
125
126 fibs = fibgen()
127
128
129
130 @lazylist
132 yield 2
133 for candidate in itertools.count(3):
134
135
136 if all(candidate % p for p in lst.computed()):
137 yield candidate
138 primes = primegen()
139
140 print fibs[0], fibs[1], fibs[2], primes[0], primes[1], primes[2]
141 print list(fibs[:10]), list(primes[:10])
142