lazy evaluation is sometimes too lazy... help please.

James Stroud jstroud at mbi.ucla.edu
Fri Jan 16 10:37:47 CET 2009


Ken Pu wrote:
> Hi,  below is the code I thought should create two generates, it[0] =
> 0,1,2,3,4,5, and it[1] = 0,10,20,30,..., but they turn out to be the
> same!!!
> 
> from itertools import *
> itlist = [0,0]
> for i in range(2):
>   itlist[i] = (x+(i*10) for x in count())
> 
> print "what's in the bags:"
> print list(islice(itlist[0], 5))
> print list(islice(itlist[1], 5))
> 
> The output is:
> [10, 11, 12, 13, 14]
> [10, 11, 12, 13, 14]
> 
> I see what Python is doing -- lazy evaluation doesn't evaluate
> (x+(i*10) for x in count()) until the end.

It doesn't evaluate it until you ask it to, which is the right behavior. 
However, when evaluated, it evaluates "i" also, which is the last value 
to which "i" was assigned, namely the integer 1. I'm going to get flamed 
pretty hard for this, but it doesn't seem to be the intuitive behavior 
to me either. However, in a purely functional language, you wouldn't be 
able to construct a list of generators in this way.

With python, you have to remember to adopt a purely functional design 
and then pray for best results. You can store generators in a list, but 
they need to be constructed properly. I can't perfectly transmogrify 
your code into functional code because I don't think making the 
particular anonymous generator you want is possible in python. However 
this is how I would make a close approximation:


from itertools import *

def make_gen(i):
   for x in count():
     yield x + (i * 10)

itlist = [make_gen(i) for i in xrange(2)]

print "what's in the bags:"
print list(islice(itlist[0], 5))
print list(islice(itlist[1], 5))


James

-- 
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com



More information about the Python-list mailing list