
At 03:47 PM 10/17/03 -0700, Guido van Rossum wrote:
Hm. What if list comprehensions returned a "lazy list", that if you took an iterator of it, you'd get a generator-iterator, but if you tried to use it as a list, it would populate itself? Then there'd be no need to ever *not* use a listcomp, and only one syntax would be necessary.
More specifically, if all you did with the list was iterate over it, and then throw it away, it would never actually populate itself. The principle drawback to this idea from a semantic viewpoint is that listcomps can be done over expressions that have side-effects. :(
I don't think this can be done without breaking b/w compatibility. Example:
a = [x**2 for x in range(10)] for i in a: print i print a
Your proposed semantics would throw away the values in the for loop, so what would it print in the third line?
I should've been more specific... some pseudocode: class LazyList(list): materialized = False def __init__(self, generator_func): self.generator = generator_func def __iter__(self): # When iterating, use the generator, unless # we've already computed contents. if self.materialized: return super(LazyList,self).__iter__() else: return self.generator() def __getitem__(self,index): if not self.materialized: self[:] = list(self.generator()) self.materialized = True return super(LazyList,self).__getitem__(index) def __len__(self): if not self.materialized: self[:] = list(self.generator()) self.materialized = True return super(LazyList,self).__len__() # etc. So, the problem isn't that the code you posted would fail on 'print a', it's that the generator function would be run *twice*, which would be a no-no if it had side effects, and would also take longer. It was just a throwaway idea, in the hopes that maybe it would lead to an idea that would actually work. Ah well, maybe in Python 3.0, there'll just be itercomps, and we'll use list(itercomp) when we want a list.