Python: Iterators and Generators

Last updated: 2026-09-22

You've been using for x in list: to iterate data, but have you ever thought about what can follow in? Why doesn't range(1000000) take up memory? Iterators and generators are the answer. They let you handle "infinite" data streams — generated on demand, not stored in memory.


Related Built-in Functions:reversed() iter() next() return yield for

1. What Is the Iterator Protocol

In Python, any object that can be used in a for loop is iterable. They implement the iterator protocol:

▶ Example: Iterator Protocol Basics

▶ Try it Yourself

Output:

TEXT 📖 Display only
# Executed successfully

A for loop essentially does this:

▶ Example: Simulating a for Loop Manually

▶ Try it Yourself

Output:

TEXT 📖 Display only
# Executed successfully


2. Custom Iterators

Implement __iter__ and __next__ to make your class work with for loops:

▶ Example: Countdown Iterator

▶ Try it Yourself

Output:

TEXT 📖 Display only
# Function defined successfully

▶ Example: Fibonacci Iterator (Difficulty ⭐⭐)

▶ Try it Yourself

Output:

TEXT 📖 Display only
# Function defined successfully


3. Generators: yield

Writing a class with __iter__ and __next__ is tedious. Generator functions use yield to achieve the same thing:

▶ Example: Countdown Generator

▶ Try it Yourself

Output:

TEXT 📖 Display only
# Function defined successfully

yield is different from return — return ends a function, while yield pauses it, remembers the current state, and resumes from where it left off on the next call.

▶ Example: Fibonacci Generator

▶ Try it Yourself

Output:

TEXT 📖 Display only
# Function defined successfully
💡 Generators vs Iterator Classes: Generator functions (yield) are usually much more concise than writing iterator classes by hand. In most scenarios, generators are the first choice. Only consider writing an iterator class if you need to maintain complex state or need additional methods.



4. Lazy Loading with Generators

The biggest advantage of generators — they don't generate all data at once, but on demand:

▶ Example: Generator Lazy Loading

▶ Try it Yourself

Output:

TEXT 📖 Display only
Generating 1
Generating 2
Generating 3
Generator created, but not yet executed

See the execution flow? Each call to next() executes up to the next yield, then pauses. This is incredibly useful for large data:

▶ Example: Reading Large Files Line by Line

▶ Try it Yourself

Output:

TEXT 📖 Display only
# Function defined successfully


5. Generator Expressions

Similar to list comprehensions, but with parentheses — generator expressions are lazily evaluated:

▶ Example: Generator Expression

▶ Try it Yourself

Output:

TEXT 📖 Display only
# Executed successfully
Comparison List Comprehension [] Generator Expression ()
Memory All data in memory On demand, almost none
Speed Fast generation and access Lazy, computes each time
Reusable Can iterate multiple times Can only iterate once
Use case Small data, repeated use Large data, single pass
💡 When to use generators? ① Large datasets (thousands+ items). ② Only need to iterate once. ③ Need streaming processing (line-by-line file, real-time data streams). ④ Want to express "infinite sequences."



6. Common Use Cases


Related Built-in Functions:reversed() iter() next() return yield for

❓ FAQ

Q What's the difference between a generator and a regular function?
A A regular function uses return to return a result once and ends. A generator uses yield to produce values one at a time, pausing and saving state after each yield. Each call to a generator function returns a new generator object.
Q Generators can only be iterated once. What if I need to iterate multiple times?
A Use list(gen) to convert the generator to a list. But if the data is too large, converting to a list will exhaust memory. A compromise: use itertools.tee() to copy the generator, or call the generator function again to create a new one.
Q Can yield and return coexist?
A Yes — return in a generator effectively stops iteration and raises StopIteration with an optional value. But it's rarely used. If you find a function needing both yield and return, reconsider the design.

📖 Summary


📝 Exercises

  1. Basic (Difficulty ⭐): Write a generator even_numbers(max_n) that generates all even numbers from 0 to max_n.

  2. Intermediate (Difficulty ⭐⭐): Write a generator repeat_list(items, times) that repeats each element of a list times times. For example, list(repeat_list([1, 2, 3], 2)) returns [1, 1, 2, 2, 3, 3].

  3. Challenge (Difficulty ⭐⭐⭐): Write a generator deep_flatten(nested) that flattens arbitrarily nested lists. For example, list(deep_flatten([1, [2, [3, 4]], 5])) returns [1, 2, 3, 4, 5]. Hint: Iterate over elements; if an element is a list, recursively yield from it with yield from.

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏