Dynamic list that automatically expands
This might get you started:
class DynamicList(list):
def __init__(self, gen):
self._gen = gen
def __getitem__(self, index):
while index >= len(self):
self.append(next(self._gen))
return super(DynamicList, self).__getitem__(index)
You'll need to add some special handling for slices (currently, they just return a normal list, so you lose the dynamic behavior). Also, if you want the generator itself to be a list item, that'll add a bit of complexity.
Just answered another similar question and decided to update my answer for you hows this?
class dynamic_list(list):
def __init__(self,num_gen):
self._num_gen = num_gen
def __getitem__(self,index):
if isinstance(index, int):
self.expandfor(index)
return super(dynamic_list,self).__getitem__(index)
elif isinstance(index, slice):
if index.stop<index.start:
return super(dynamic_list,self).__getitem__(index)
else:
self.expandfor(index.stop if abs(index.stop)>abs(index.start) else index.start)
return super(dynamic_list,self).__getitem__(index)
def __setitem__(self,index,value):
if isinstance(index, int):
self.expandfor(index)
return super(dynamic_list,self).__setitem__(index,value)
elif isinstance(index, slice):
if index.stop<index.start:
return super(dynamic_list,self).__setitem__(index,value)
else:
self.expandfor(index.stop if abs(index.stop)>abs(index.start) else index.start)
return super(dynamic_list,self).__setitem__(index,value)
def expandfor(self,index):
rng = []
if abs(index)>len(self)-1:
if index<0:
rng = xrange(abs(index)-len(self))
else:
rng = xrange(abs(index)-len(self)+1)
for i in rng:
self.append(self._num_gen.next())
Many thanks to all who contributed ideas! Here's what I have gathered together from all the responses. This retains most functionality from the normal list class, adding additional behaviours where necessary to meet additional requirements.
class DynamicList(list):
def __init__(self, gen):
self.gen = gen
def __getitem__(self, index):
while index >= len(self):
self.append(next(self.gen))
return super(DynamicList, self).__getitem__(index)
def __getslice__(self, start, stop):
# treat request for "last" item as "most recently fetched"
if stop == 2147483647: stop = len(self)
while stop > len(self):
self.append(next(self.gen))
return super(DynamicList, self).__getslice__(start, stop)
def __iter__(self):
return self
def next(self):
n = next(self.gen)
self.append(n)
return n
a = DynamicList(iter(xrange(10)))
Previously generated values can be accessed individually as items or slices. The recorded history expands as necessary if the requested item(s) are beyond the current end of the list. The entire recorded history can be accessed all at once, using print a
, or assigned to a normal list using b = a[:]
. A slice of the recorded history can be deleted using del a[0:4]
. You can iterate over the whole list using for
, deleting as you go, or whenever it suits. Should you reach the end of the generated values, StopIteration
is raised.
Some awkwardness remains. Assignments like a = a[0:4]
successfully truncate the history, but the resulting list no longer auto-expands. Instead use del a[0:4]
to retain the automatic growth properties. Also, I'm not completely happy with having to recognise a magic value, 2147483647
, representing the most recent item.