Package lastfm :: Module lazylist
[hide private]
[frames] | no frames]

Source Code for Module lastfm.lazylist

  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 
13 14 -class LazyList(object):
15 """A Sequence whose values are computed lazily by an iterator. 16 """
17 - def __init__(self, iterable):
18 self._exhausted = False 19 self._iterator = iter(iterable) 20 self._data = []
21
22 - def __len__(self):
23 """Get the length of a LazyList's computed data.""" 24 return len(self._data)
25
26 - def __getitem__(self, i):
27 """Get an item from a LazyList. 28 i should be a positive integer or a slice object.""" 29 if isinstance(i, int): 30 #index has not yet been yielded by iterator (or iterator exhausted 31 #before reaching that index) 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 #LazyList slices are iterators over a portion of the list. 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 #set start and step to their integer defaults if they are None. 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 #slices can go out of actual index range without raising an 57 #error 58 except IndexError: 59 break 60 count += step
61 return LazyListIterator() 62 63 raise TypeError('i must be an integer or slice')
64
65 - def __iter__(self):
66 """return an iterator over each value in the sequence, 67 whether it has been computed yet or not.""" 68 return self[:]
69
70 - def computed(self):
71 """Return an iterator over the values in a LazyList that have 72 already been computed.""" 73 return self[:len(self)]
74
75 - def exhaust(self, index = None):
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: #iterator is fully exhausted 92 self._exhausted = True 93 break
94
95 -class RecursiveLazyList(LazyList):
96 - def __init__(self, prod, *args, **kwds):
97 super(RecursiveLazyList,self).__init__(prod(self,*args, **kwds))
98
99 - def __repr__(self):
100 return "<lastfm.lazylist>"
101
102 -class RecursiveLazyListFactory:
103 - def __init__(self, producer):
104 self._gen = producer
105 - def __call__(self,*a,**kw):
106 return RecursiveLazyList(self._gen,*a,**kw)
107
108 109 -def lazylist(gen):
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 #two examples 117 if __name__ == '__main__': 118 #fibonnacci sequence in a lazy list. 119 @lazylist
120 - def fibgen(lst):
121 yield 0 122 yield 1 123 for a, b in itertools.izip(lst, lst[1:]): 124 yield a + b
125 126 fibs = fibgen() #now fibs can be indexed or iterated over as if it were 127 #an infinitely long list containing the fibonnaci sequence 128 129 #prime numbers in a lazy list. 130 @lazylist
131 - def primegen(lst):
132 yield 2 133 for candidate in itertools.count(3): #start at next number after 2 134 #if candidate is not divisible by any smaller prime numbers, 135 #it is a prime. 136 if all(candidate % p for p in lst.computed()): 137 yield candidate
138 primes = primegen() #same for primes- treat it like an infinitely long list 139 #containing all prime numbers. 140 print fibs[0], fibs[1], fibs[2], primes[0], primes[1], primes[2] 141 print list(fibs[:10]), list(primes[:10]) 142