Reputation: 141
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
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
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:
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:
and then do the sum.
Upvotes: 1