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

Michael Hartl mikehartl at web.de
Fri Jan 16 05:17:18 EST 2009


James Stroud schrieb:
> 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
>
You could just as well use the original expression in make_gen, too:

from itertools import *
def make_gen(i):
  return (x + (i*10) for x in count())

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))

what's in the bags:
[0, 1, 2, 3, 4]
[10, 11, 12, 13, 14]



More information about the Python-list mailing list