Python
generator
programming
reset generator
code tutorial

Resetting generator object in Python

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

You cannot reset a consumed Python generator object back to the beginning. A generator is stateful by design: once it advances, that internal execution state moves forward until exhaustion. If you need restartable iteration, the solution is usually to create a new generator object or wrap the logic in an iterable that can produce fresh generators on demand.

Why Generators Cannot Be Reset

A generator remembers its current execution point, local variables, and pending yield position. Python does not expose an API to rewind that state.

python
1def numbers():
2    yield 1
3    yield 2
4    yield 3
5
6g = numbers()
7print(next(g))
8print(next(g))

At this point, g is already partway through the function. There is no built-in reset() method to send it back to the first yield.

Create a New Generator Instead

The normal reset pattern is simply to call the generator function again.

python
1def numbers():
2    yield 1
3    yield 2
4    yield 3
5
6g = numbers()
7print(list(g))
8
9g = numbers()  # fresh generator
10print(list(g))

This works because generator functions are factories for generator objects. The function stays reusable even though each generator instance is single-pass.

Wrap the Sequence in an Iterable Class

If you need something that can be iterated multiple times without the caller worrying about recreation, use a custom iterable class that returns a new generator from __iter__.

python
1class Countdown:
2    def __init__(self, start):
3        self.start = start
4
5    def __iter__(self):
6        for n in range(self.start, 0, -1):
7            yield n
8
9values = Countdown(3)
10print(list(values))
11print(list(values))

The object itself is reusable because each iteration gets a fresh generator.

Materialize Results If Replay Is Required

If the underlying computation is expensive and the result set is finite, sometimes the correct answer is not "reset the generator" but "store the generated values".

python
1def squares():
2    for n in range(5):
3        yield n * n
4
5cached = list(squares())
6print(cached)
7print(cached)

That trades memory for replayability. It is appropriate when the sequence is small or repeated access matters more than streaming behavior.

itertools.tee Is Not a True Reset

itertools.tee can split one iterator into multiple independent iterators, but it is not a general reset mechanism.

python
1import itertools
2
3def letters():
4    for ch in "abc":
5        yield ch
6
7g1, g2 = itertools.tee(letters(), 2)
8print(next(g1))
9print(list(g2))

This duplicates iteration state forward from the current point. It does not rewind an already-consumed generator back to the start.

Choose the Right Design

Ask what you actually need:

  1. single-pass streaming
  2. repeatable iteration
  3. cached results for reuse

If repeatability is required, a bare generator object is often the wrong abstraction to hand around long-term.

That design choice becomes even more important in APIs. Returning a generator object from a function is perfect for streaming, but it can surprise callers if they assume they can iterate the result multiple times like a list.

Common Pitfalls

  • Looking for a reset() method on generator objects.
  • Passing around one generator instance when the caller really needs repeatable iteration.
  • Using itertools.tee as if it rewinds an exhausted generator.
  • Materializing an enormous generator into a list without considering memory cost.
  • Forgetting that calling the generator function again creates a fresh iterator.

Another common mistake is storing a generator as an object attribute and then expecting every method call to start from the beginning. If repeatability matters, store the generator function or the source data instead.

Summary

  • Python generators are single-pass objects and cannot be reset in place.
  • The normal reset strategy is to create a new generator object.
  • If callers need repeatable iteration, expose an iterable that creates fresh generators.
  • Use caching only when replay is needed and the data size makes that reasonable.
  • Choose the abstraction based on whether streaming or reuse is the real requirement.

Course illustration
Course illustration

All Rights Reserved.