3

I thought the "for in" statement takes in iterables not iterators, but somehow the following codes works fine. I am confused. Actually, I was looking at the generator example at : https://www.python.org/dev/peps/pep-0289/

>>> for i in range(10):
    print(i)


0
1
2
3
4
5
6
7
8
9
>>> for i in iter(range(10)):
    print(i)


0
1
2
3
4
5
6
7
8
9
>>>

Anyone can explain what happened when using iter(range(10)) in the for loop?

1
  • iterators are iterables. Commented Jul 11, 2018 at 22:02

1 Answer 1

9

Iterators are iterables too. for calls iter() on the object it iterates over, and if you already have an iterator, then that produces a reference to the same object. This is by design.

From the iterator entry in the Python glossary:

Iterators are required to have an __iter__() method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted.

Bold emphasis mine.

From the same document, on the term iterable:

When using iterables, it is usually not necessary to call iter() or deal with iterator objects yourself. The for statement does that automatically for you, creating a temporary unnamed variable to hold the iterator for the duration of the loop.

and from the Iterator types section of the standard types document:

The iterator objects themselves are required to support the following two methods, which together form the iterator protocol:

iterator.__iter__()

Return the iterator object itself. This is required to allow both containers and iterators to be used with the for and in statements.

Bold emphasis mine.

So when you use for ... in iter(range(...)) instead of for ... in range(), you make an extra call to iter() that's basically redundant, as for already makes that call itself.

But you can use iter() before you use a for loop to keep a reference to the iterator; so you could use it to advance to the next value elsewhere, in coordination with the for loop:

>>> range_iter = iter(range(10))
>>> for i in range_iter:
...     print('for loop produced', i)
...     if i % 4 == 0:
...         j = next(range_iter)
...         print('But we can advance the iterator manually, too:', j)
...
for loop produced 0
But we can advance the iterator manually, too: 1
for loop produced 2
for loop produced 3
for loop produced 4
But we can advance the iterator manually, too: 5
for loop produced 6
for loop produced 7
for loop produced 8
But we can advance the iterator manually, too: 9

In the PEP, in the detail section, the code example there uses an iter() call before calling the generator function, because that iter() call could potentially raise an exception. You'd want that exception to be raised when defining the generator expression, not later on when you try to iterate over the generator expression.

Or put concretely, the following code fails on the first line, not during looping:

gen = (x ** 2 for x in 1)  # 1 is not an iterable
for i in gen: print(i)

If the implementation did not call iter() first, then only when the for loop executes would there be an exception, and that would be confusing because the gen reference could have been created in any number of places in the code, really.

Sign up to request clarification or add additional context in comments.

3 Comments

then why bother using iter(range(10)) in the generator example in the hyperlink?
@OpticalDataScience: because the PEP documents that the internal workings of the generator expression implementation will create an iterator before calling the generator function object. The actual implementation doesn't use a for loop, it generates bytecode that is roughly equivalent.
@OpticalDataScience: this matters when you use that generator expression at a later point in your code. If the iter() call fails, it'll fail at the point where the generator expression is defined, not where you eventually iterate over it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.