mwlow
mwlow

Reputation: 141

list generator confusion

Been reading Pep-0289. It mentions that

sum(x*x for x in range(10))

will conserve memory over this:

sum([x*x for x in range(10)])

What I'm confused about is why range(10) won't generate the entire list at once. Is there something where, if you throw range() in the for-each construction, it automatically becomes an iterator? I thought the answer was no, because that is what xrange() in Python 2.x is for.

Further down the Pep it says:

def __gen(exp):
    for x in exp:
        yield x**2
g = __gen(iter(range(10)))
print g.next()

Here they use iter to turn range(10) into an iterator. Why is iter not needed in the earlier examples? Are [x for x in range(3)] and [x for x in iter(range(3))] somehow treated the same?

Upvotes: 2

Views: 78

Answers (2)

user2555451
user2555451

Reputation:

Are [x for x in [1, 3, 4]] and [x for x in iter([1, 3, 4])] somehow treated the same?

They have the same effect, yes. The line:

[x for x in [1, 3, 4]]

implicitly calls the list's __iter__ method to get an iterator over it. It is equivalent to this:

[x for x in [1, 3, 4].__iter__()]

This line however:

[x for x in iter([1, 3, 4])]

uses iter to get an iterator over the list. It also is equivalent to:

[x for x in [1, 3, 4].__iter__()]

except that it unnecessarily uses the built-in iter function to do what the for ... in ... clause does already.


A better use of iter is to control iteration over an iterable step-by-step. Below is an example:

it = iter(iterable)
item = next(it)  # Get the first item in the iterator
while True:
    # code
    if condition:
        item = next(it)  # Advance the iterator only if condition is True

Upvotes: 1

Gerrat
Gerrat

Reputation: 29740

range(10) will generate the entire list at once. That's not the memory-conserving part though.

This:

sum(x*x for x in range(10))

will basically calculate (more or less) as follows:

  • cur_sum = 1*1
  • cur_sum = cur_sum + 2*2
  • ...
  • cur_sum = cur_sum + 9*9

That is it will calculate each individually, and sum as it goes along

The following:

sum([x*x for x in range(10)])

Instead will create an entire list first of:

  • [1*1, 2*2, 3*3...9*9]

and then do the sum.

Upvotes: 1

Related Questions