Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

Why can I use an iterator once but get nothing the second time?

Quick answer

An iterator supplies values as you retrieve them. Once exhausted, it does not rewind when you start another loop. A list is a reusable container: each loop over it can get a fresh iterator. To make two passes, keep the values in a list before consuming them, or create a fresh iterator from a source that can produce the values again.

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

I loop over some Python data once and get the expected values. When I run the loop again, nothing appears. Why?

Geez

You may be reusing an iterator that has already been consumed. An iterator supplies values successively; after its items have been retrieved, it is exhausted. Starting another for loop does not rewind it. [S1]

This runnable example shows the first pass and the empty second pass:

numbers = iter([10, 20, 30])

print("First pass:")
for number in numbers:
    print(number)

print("Second pass:")
for number in numbers:
    print(number)

The first loop prints 10, 20, and 30; the second prints nothing. Both loops use the same iterator, and the first loop retrieved all its values. A list behaves differently, so the important distinction is what the variable refers to.

Follow-up question

Would the same two loops work if I used a list instead?

Geez

Yes. A list is a reusable container: each loop over it can get a fresh iterator, so both passes can visit the values. [S1]

numbers = [10, 20, 30]

for number in numbers:
    print("First pass:", number)

for number in numbers:
    print("Second pass:", number)

Both loops print all three numbers. In contrast, numbers = iter([10, 20, 30]) makes numbers an iterator, which the first loop consumes. You can check what a variable refers to with print(type(numbers)); use that as a debugging clue, then check how the object is being used.

Follow-up question

I need to process the same values twice. What is a practical fix?

Geez

For a finite set of values you want to reuse, put them in a list before the first pass. If you already have an iterator, converting it to a list retrieves its available values, so do this before consuming values you need to keep:

source = iter(["red", "green", "blue"])
values = list(source)

for value in values:
    print("First pass:", value)

for value in values:
    print("Second pass:", value)

Both loops use the reusable list values. If the iterator was partly consumed before list(source), the list contains only values still available from it.

If you can produce the values again, you can instead create a fresh iterator for each pass:

def make_numbers():
    return iter([10, 20, 30])

for number in make_numbers():
    print("First:", number)

for number in make_numbers():
    print("Second:", number)

Use a list when you need to retain the values; use a fresh iterator when you can readily produce them again.

Follow-up question

What should I check if the second pass is still empty?

Geez

Check the exact variable used in each loop. Make sure the second pass uses the list or newly created iterator you intended, rather than the same exhausted iterator. A common mistake is converting the iterator to a list after the first pass; then only values still available can be copied.

Also check whether an assignment such as values = iter(values) changed the variable you reuse. If you need the complete set for both passes, create the list before the first loop. The practical rule is: an iterator is consumed as you retrieve its values; use a reusable list or create a fresh iterator when you need another pass. [S1]

A practical checklist

  • Check whether both loops use the same iterator.

  • For two passes, keep the values in a list before consuming them.

  • If you can produce the values again, create a fresh iterator for each pass.

  • When converting an iterator to a list, remember it contains only values still available.

A few more useful answers

Does starting a new `for` loop rewind an iterator?

No. A new loop does not rewind the same exhausted iterator. Use a reusable container or create a fresh iterator from a source that can produce the values again. [S1]

Can I turn an exhausted iterator into a list to recover its original values?

No. Converting it to a list retrieves only values still available from that iterator. Make the list before consuming the values you need, or produce them again.

Is every iterable reusable like a list?

Do not assume so. A list produces a fresh iterator for each loop, but other objects may behave differently. [S1]

Sources

References used for this guide.

  1. [S1] Python Glossary: iterator and container
    docs.python.org · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work